Spring 高级 Scope失效解决
一、面试问题
1、如果一个单例Bean里面 注入多例 通过单例Bean对象获取到的多例Bean是单例还是多例
二、 失效演示
1、代码
package com.mangoubiubiu.show.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; } }
package com.mangoubiubiu.show.a09; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Scope("prototype") @Component public class F1 { }
package com.mangoubiubiu.show.a09; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; @ComponentScan("com.mangoubiubiu.show.a09") @Slf4j public class A09Application { public static void main(String [] aras){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class); E e = context.getBean(E.class); log.info("{}",e.getF1()); log.info("{}",e.getF1()); log.info("{}",e.getF1()); log.info("{}",e.getF1()); log.info("{}",e.getF1()); context.close(); } }
发现它们是同一个对象,而不是期望的多例对象
对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 F,因此 E 用的始终是第一次依赖注入的 F
二、 失效解决方案
1、使用 @Lazy 生成代理
- 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象
package com.mangoubiubiu.show.a09; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class E { @Autowired @Lazy private F1 f1; public F1 getF1(){ return f1; } }
发现获取到的是不同的实例Bean
2、@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) 生成代理
在目标类上加
package com.mangoubiubiu.show.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 F1 { }
package com.mangoubiubiu.show.a09; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class E { @Autowired // @Lazy private F1 f1; public F1 getF1(){ return f1; } }
发现获取到的是不同的实例Bean
3、使用对象工厂ObjectFactory获取多实例Bean
package com.mangoubiubiu.show.a09; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class E { // @Autowired //// @Lazy // private F1 f1; // public F1 getF1(){ // return f1; // } @Autowired private ObjectFactory<F1> f1; public F1 getF1(){ return f1.getObject(); } }
发现获取到的是不同的实例Bean
4、通过容器拿多例Bean
package com.mangoubiubiu.show.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 { // @Autowired //// @Lazy // private F1 f1; // public F1 getF1(){ // return f1; // } // @Autowired // private ObjectFactory<F1> f1; // // public F1 getF1(){ // return f1.getObject(); // } @Autowired private ApplicationContext context; public F1 getF1(){ return context.getBean(F1.class); } }
收获💡
- 单例注入其它 scope 的四种解决方法
- @Lazy
- @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
- ObjectFactory
- ApplicationContext
- 解决方法虽然不同,但理念上殊途同归: 都是推迟其它 scope bean 的获取