您好,登录后才能下订单哦!
今天小编给大家分享一下Spring怎么控制Bean注入的顺序的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
说明
首先需要说明的是:在Bean上加@Order(xxx)是无法控制bean注入的顺序的!
控制bean的加载顺序的方法
1.构造方法依赖
2.@DependsOn 注解
3.BeanPostProcessor 扩展
Bean初始化顺序与类加载顺序基本一致:静态变量/语句块=> 实例变量或初始化语句块=> 构造方法=> @Autowirebean注入的顺序
创建两个Bean,要求CDemo2在CDemo1之前被初始化。
@Component public class CDemo1 { private String name = "cdemo 1"; public CDemo1(CDemo2 cDemo2) { System.out.println(name); } } @Component public class CDemo2 { private String name = "cdemo 2"; public CDemo2() { System.out.println(name); } }
结果(和预期一致)
限制
要有注入关系,如:CDemo2通过构造方法注入到CDemo1中,若需要指定两个没有注入关系的bean之间优先级,则不太合适(比如我希望某个bean在所有其他的Bean初始化之前执行)
循环依赖问题,如过上面的CDemo2的构造方法有一个CDemo1参数,那么循环依赖产生,应用无法启动
另外一个需要注意的点是,在构造方法中,不应有复杂耗时的逻辑,会拖慢应用的启动时间
不推荐的原因:这种方法是通过bean的名字(字符串)来控制顺序的,如果改了bean的类名,很可能就会忘记来改所有用到它的注解,那就问题大了。
当一个bean需要在另一个bean实例化之后再实例化时,可使用这个注解。
@DependsOn("rightDemo2") @Component public class RightDemo1 { private String name = "right demo 1"; public RightDemo1() { System.out.println(name); } } @Component public class RightDemo2 { private String name = "right demo 2"; public RightDemo2() { System.out.println(name); } }
上面的注解放在 RightDemo1 上,表示RightDemo1的初始化依赖于rightDemo2这个bean
它能控制bean的实例化顺序,但是bean的初始化操作(如构造bean实例之后,调用@PostConstruct注解的初始化方法)顺序则不能保证,比如我们下面的一个实例,可以说明这个问题
@DependsOn("rightDemo2") @Component public class RightDemo1 { private String name = "right demo 1"; @Autowired private RightDemo2 rightDemo2; public RightDemo1() { System.out.println(name); } @PostConstruct public void init() { System.out.println(name + " _init"); } } @Component public class RightDemo2 { private String name = "right demo 2"; @Autowired private RightDemo1 rightDemo1; public RightDemo2() { System.out.println(name); } @PostConstruct public void init() { System.out.println(name + " _init"); } }
结果(先实例的Bean反而在后边执行init)
把上面测试代码中的@Autowired的依赖注入删除,即两个bean没有相互注入依赖,再执行,会发现输出顺序又不一样
一种非典型的使用方式,如非必要,请不要用这种方式来控制bean的加载顺序。
场景1:希望HDemo2在HDemo1之前被加载
@Component public class HDemo1 { private String name = "h demo 1"; public HDemo1() { System.out.println(name); } } @Component public class HDemo2 { private String name = "h demo 2"; public HDemo2() { System.out.println(name); } }
@Component public class DemoBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) { if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { throw new IllegalArgumentException( "AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory); } this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } @Override @Nullable public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { // 在bean实例化之前做某些操作 if ("HDemo1".equals(beanName)) { HDemo2 demo2 = beanFactory.getBean(HDemo2.class); } return null; } }
将目标集中在postProcessBeforeInstantiation,这个方法在某个bean的实例化之前,会被调用,这就给了我们控制bean加载顺序的机会。
执行结果
场景2:希望某个bean在应用启动之后,首先实例化此Bean。
解决方法:重写DemoBeanPostProcessor的postProcessAfterInstantiation方法。
@Component public class DemoBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if ("application".equals(beanName)) { beanFactory.getBean(FDemo.class); } return true; } } @DependsOn("HDemo") @Component public class FDemo { private String name = "F demo"; public FDemo() { System.out.println(name); } } @Component public class HDemo { private String name = "H demo"; public HDemo() { System.out.println(name); } }
执行结果(HDemo, FDemo的实例化顺序放在了最前面)
以上就是“Spring怎么控制Bean注入的顺序”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。