Scope
- 1.Scope类型有哪些
- 2.在singleton中使用其它几种scope的注意事项
- 3.scope的销毁
- 4.实战:scope失效分析
解决方法虽然不同,但理念上殊途同归:都是推迟其它scope bean的获取
Scope
A08Application.java
java
package com.lucifer.itheima.a08;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/*
singleton(获取bean的时候,每次从容器返回的都是同一个对象),prototype(每次到容器中获取bean的时候都会产生一个新的对象),request
(bean存在于request域中,每次请求来了,会把这个bean放在request域中,请求结束bean的生命周期也随之结束),
session(会话域,同一个会话内,会话开始bean被创建,会话结束bean被销毁),
application(应用程序域,应用程序启动时,这个域被创建,应用程序销毁时,被销毁,这里的应用程序指的是web中的servletContext)
演示 request,session,application作用域
打开不同的浏览器,刷新http://localhost:8080/test即可查看效果
如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED
*/
@SpringBootApplication
public class A08Application {
public static void main(String[] args) {
SpringApplication.run(A08Application.class,args);
}
//请求访问http://localhost:4580/lucifer98/test的结果是
// request scope:com.lucifer.itheima.a08.BeanForRequest@51d9e461
// session scope:com.lucifer.itheima.a08.BeanForSession@65784f1f
// application scope:com.lucifer.itheima.a08.BeanForApplication@30d82692
}
MyController.java
java
package com.lucifer.itheima.a08;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@RestController
public class MyController {
@Lazy
@Autowired
private BeanForRequest beanForRequest;
@Lazy
@Autowired
private BeanForSession beanForSession;
@Lazy
@Autowired
private BeanForApplication beanForApplication;
@GetMapping(value = "/test",produces = "text/html")
public String test(HttpServletRequest request, HttpSession session) {
ServletContext sc = request.getServletContext();
String sb = "<ul>" +
"<li>" + "request scope:" + beanForRequest + "</li>" +
"<li>" + "session scope:" + beanForSession +"</li>" +
"<li>" + "application scope:" + beanForApplication + "</li>" +
"</ul>";
return sb;
}
}
BeanForApplication.java
java
package com.lucifer.itheima.a08;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@Slf4j
@Scope("application")
@Component
public class BeanForApplication {
@PreDestroy
public void destroy(){
log.info("destroy");
}
}
BeanForRequest.java
java
package com.lucifer.itheima.a08;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@Scope("request")
@Component
@Slf4j
public class BeanForRequest {
@PreDestroy
public void destroy(){
log.info("destroy");
}
}
BeanForSession.java
java
package com.lucifer.itheima.a08;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@Slf4j
@Scope("session")
@Component
public class BeanForSession {
@PreDestroy
public void destroy(){
log.info("destroy");
}
}
Scope失效解决--@Lazy、@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)、ObjectFactory、ApplicationContext
A09Application.java
java
package com.lucifer.itheima.a09;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/*
如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED
*/
@ComponentScan("com.lucifer.itheima.a09")
@Slf4j
public class A09Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);
// 输出结果为
// 11:58:35.868 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@1f1c7bf6
// 11:58:35.870 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@1f1c7bf6
// 11:58:35.870 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@1f1c7bf6
// F1配置的是多例(@Scope("prototype")),没用一次希望是不同对象,但是F1此时打印出来的是同一个。所以多例配置失效了 即发现他们是同一个对象,而不是期望的多例对象
// 对于单例对象来讲,依赖注入仅发生了一次,后续再没用到多例的F,因此E用的始终是第一次依赖注入的F
//解决
//使用@Lazy生成代理
//代理对象虽然还是同一个,但是每次使用代理对象的任意方法时,由代理创建新的f对象
E e = context.getBean(E.class);
log.info("{}",e.getF1());
log.info("{}",e.getF1());
log.info("{}",e.getF1());
context.close();
}
}
E.java
java
package com.lucifer.itheima.a09;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class E {
@Autowired
private F1 f1;
public F1 getF1(){
return f1;
};
}
F1.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class F1 {
}
解决1
- 使用@Lazy生成代理
- 代理对象虽然还是同一个,但是每次使用代理对象的任意方法时,由代理创建新的f对象
E.java
java
package com.lucifer.itheima.a09;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
public class E {
@Lazy
@Autowired
private F1 f1;
public F1 getF1(){
return f1;
};
}
解决2
- 使用@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)生成代理
A09Application.java
java
package com.lucifer.itheima.a09;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/*
如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED
*/
@ComponentScan("com.lucifer.itheima.a09")
@Slf4j
public class A09Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);
// 输出结果为
// 14:29:03.623 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
// .F1$$EnhancerBySpringCGLIB$$d0e56e2e //代理对象
// 14:29:03.624 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@16ec5519
// 不同的对象
// 14:29:03.631 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@188715b5
// 14:29:03.632 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@6a192cfe
E e = context.getBean(E.class);
//这个是个代理对象
log.info("{}",e.getF1().getClass());
log.info("{}",e.getF1());
log.info("{}",e.getF1());
log.info("{}",e.getF1());
//F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之前
// 输出结果为
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09.F2
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
// 相同的对象
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
//F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之后
//输出结果为
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
// .F2$$EnhancerBySpringCGLIB$$5eea9055 //代理对象
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@5c33f1a9
// 不同的对象
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@1623b78d
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@c8c12ac
log.info("{}",e.getF2().getClass());
log.info("{}",e.getF2());
log.info("{}",e.getF2());
log.info("{}",e.getF2());
context.close();
}
}
E.java
java
package com.lucifer.itheima.a09;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
public class E {
@Lazy
@Autowired
private F1 f1;
@Autowired
private F2 f2;
public F1 getF1(){
return f1;
}
public F2 getF2(){
return f2;
}
}
F1.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class F1 {
}
F2.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}
解决3,4
- 使用ObjectFactory、ApplicationContext间接获取多例
A09Application.java
java
package com.lucifer.itheima.a09;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/*
如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED
*/
@ComponentScan("com.lucifer.itheima.a09")
@Slf4j
public class A09Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);
// 输出结果为
// 14:29:03.623 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
// .F1$$EnhancerBySpringCGLIB$$d0e56e2e //代理对象
// 14:29:03.624 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@16ec5519
// 不同的对象
// 14:29:03.631 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@188715b5
// 14:29:03.632 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@6a192cfe
E e = context.getBean(E.class);
//这个是个代理对象
log.info("{}",e.getF1().getClass());
log.info("{}",e.getF1());
log.info("{}",e.getF1());
log.info("{}",e.getF1());
//F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之前
// 输出结果为
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09.F2
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
// 相同的对象
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
// 15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
//F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之后
//输出结果为
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
// .F2$$EnhancerBySpringCGLIB$$5eea9055 //代理对象
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@5c33f1a9
// 不同的对象
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@1623b78d
// 15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@c8c12ac
log.info("{}",e.getF2().getClass());
log.info("{}",e.getF2());
log.info("{}",e.getF2());
log.info("{}",e.getF2());
//输出结果为
// 16:42:03.962 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F3@72967906
// 是不同的f3
// 16:42:03.963 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F3@2f9f7dcf
log.info("{}",e.getF3());
log.info("{}",e.getF3());
// 输出结果为
// 16:50:29.108 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F4@42a48628 //
// 不同的对象
// 16:50:29.108 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F4@293a5bf6
log.info("{}",e.getF4());
log.info("{}",e.getF4());
context.close();
}
}
E.java
java
package com.lucifer.itheima.a09;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
public class E {
@Lazy
@Autowired
private F1 f1;
@Autowired
private F2 f2;
@Autowired
private ObjectFactory<F3> f3;
@Autowired
private ApplicationContext context;
public F1 getF1(){
return f1;
}
public F2 getF2(){
return f2;
}
public F3 getF3(){
return f3.getObject();
}
public F4 getF4(){
return context.getBean(F4.class);
}
}
F1.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class F1 {
}
F2.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}
F3.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class F3 {
}
F4.java
java
package com.lucifer.itheima.a09;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class F4 {
}