Spring怎么控制Bean注入的顺序
今天小编给大家分享一下Spring怎么控制Bean注入的顺序的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
简介
说明
首先需要说明的是:在Bean上加@Order(xxx)是无法控制bean注入的顺序的!
控制bean的加载顺序的方法
构造方法依赖
@DependsOn 注解
BeanPostProcessor 扩展
Bean初始化顺序与类加载顺序基本一致:静态变量/语句块=> 实例变量或初始化语句块=> 构造方法=> @Autowirebean注入的顺序
构造方法依赖(推荐)
创建两个Bean,要求CDemo2在CDemo1之前被初始化。
@Componentpublic class CDemo1 { private String name = "cdemo 1"; public CDemo1(CDemo2 cDemo2) { System.out.println(name); }} @Componentpublic class CDemo2 { private String name = "cdemo 2"; public CDemo2() { System.out.println(name); }}
结果(和预期一致)
限制
要有注入关系,如:CDemo2通过构造方法注入到CDemo1中,若需要指定两个没有注入关系的bean之间优先级,则不太合适(比如我希望某个bean在所有其他的Bean初始化之前执行)
循环依赖问题,如过上面的CDemo2的构造方法有一个CDemo1参数,那么循环依赖产生,应用无法启动
另外一个需要注意的点是,在构造方法中,不应有复杂耗时的逻辑,会拖慢应用的启动时间
@DependsOn(不推荐)
不推荐的原因:这种方法是通过bean的名字(字符串)来控制顺序的,如果改了bean的类名,很可能就会忘记来改所有用到它的注解,那就问题大了。
当一个bean需要在另一个bean实例化之后再实例化时,可使用这个注解。
@DependsOn("rightDemo2")@Componentpublic class RightDemo1 { private String name = "right demo 1"; public RightDemo1() { System.out.println(name); }} @Componentpublic class RightDemo2 { private String name = "right demo 2"; public RightDemo2() { System.out.println(name); }}
上面的注解放在 RightDemo1 上,表示RightDemo1的初始化依赖于rightDemo2这个bean
它能控制bean的实例化顺序,但是bean的初始化操作(如构造bean实例之后,调用@PostConstruct注解的初始化方法)顺序则不能保证,比如我们下面的一个实例,可以说明这个问题
@DependsOn("rightDemo2")@Componentpublic 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"); }} @Componentpublic 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没有相互注入依赖,再执行,会发现输出顺序又不一样
BeanPostProcessor(不推荐)
一种非典型的使用方式,如非必要,请不要用这种方式来控制bean的加载顺序。
场景1:希望HDemo2在HDemo1之前被加载
@Componentpublic class HDemo1 { private String name = "h demo 1"; public HDemo1() { System.out.println(name); }} @Componentpublic class HDemo2 { private String name = "h demo 2"; public HDemo2() { System.out.println(name); }}
@Componentpublic 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方法。
@Componentpublic 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")@Componentpublic class FDemo { private String name = "F demo"; public FDemo() { System.out.println(name); }} @Componentpublic class HDemo { private String name = "H demo"; public HDemo() { System.out.println(name); }}
执行结果(HDemo, FDemo的实例化顺序放在了最前面)
以上就是“Spring怎么控制Bean注入的顺序”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341