单例作用域
原型作用域
web作用域,请求作用域,生命周期跟request相同,请求开始bean被创建,请求结束bean被销毁
web作用域,会话作用域,会话开始bean被创建,会话结束bean被销毁
web作用域,应用程序作用域,应用程序创建bean呗创建,应用程序销毁bean被销毁。应用程序指的是Web的ServerletContext
singleton中使用其他类型Scope
在单例作用域bean中使用其他类型的作用域的bean,会导致作用域失效(可以这么理解吧),例如单例作用域的bean注入原型作用域的bean。(A单例,B原型)
@Component
@Data
public class A {@Autowiredprivate B b;}
@Component
@Scope("prototype")
public class B {
}
测试代码
private static void d() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Ceshi.class);A bean = context.getBean(A.class);System.out.println(bean.getB());System.out.println(bean.getB());}
Ceshi.class类扫描A.class和B.class所在的包,测试结果如下
com.example.springtest.c.B@273e7444
com.example.springtest.c.B@273e7444
预期结果是单例A getB()得到两个不同的Bean,实际结果是得到了同一个bean,这明显是错误的,因为B bean是原型作用域
失效分析
对于单例对象来讲,依赖注入只发生一次,因此在单例对象中拿到的其他作用域bean时始终是同一个
解决方案
添加@Lazy注解
在@Scope注解上添加参数
@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
这两个解决方式都是利用代理解决,每次拿到的对象是代理对象,利用代理解决效率理论上不如下边两种解决方案
用工厂方法
@Autowired
private ObjectFactory b1;public B getB1(){return b1.getObject();
}
用容器
@Autowired
private ApplicationContext context;public B getB2(){return context.getBean(B.class);
}
4种解决方案的核心思想都是推迟bean的获取