【JAVA】自记-常见Spring坑-bean加载顺序

87 阅读2分钟

背景

前面搓热更新,搓到starter模块以接入已有spring工程时,有个诉求:

  • 定时扫描热更新调度任务并判断自己是否需要执行的bean①, 和 ,重启时自动判断app版本恢复热更新进度的bean②,之间存在顺序要求
  • 这个要求说大也大说小也小,其实不做也没什么,但既然想到了就尝试控制顺序了。
  • (1)希望启动时先完成②,再进行①,预防并发问题
  • (2)希望②发生在所有spring bean最优先进行

坑1:@Order别瞎用

CSDN会告诉你@Order,但你印象中是不是从来没生效过?

以前都力大砖飞的@DependsOn/@Autowired显式声明依赖关系以让Spring分析知道这个事,直接解决的。 还可以@Bean方法,但本质一样。

但是为啥@Order没用?

因为@Order只是个用于控制List<?>的顺序的注解,生效范围都是Spring开的口子指定接口的实现或动态代理元素的list

引用 java - 如何正确控制springboot中bean的加载顺序总结 - 个人文章 - SegmentFault 思否

image.png

坑2:如何最优先/最不优先/控制加载顺序?

这个问题有几个发散方向:

1、在spring预留口子里操作,比如

最优先:实现 BeanDefinitionRegistryPostProcessor 手动注册 或 BeanFactoryPostProcessor也大差不差

最不优先:希望最后执行,好像没明确的postProcessor对应这种场景

那么看bean工厂启动流程,随便列几个口子,比如

(1)实现自定义org.springframework.boot.SpringApplication#afterRefresh image.png (2)监听上下文context刷新事件 org.springframework.context.support.AbstractApplicationContext#finishRefresh image.png

2、定制并重写spring的bean注册逻辑?比如list排序策略?这恐怕有些复杂了,因为要梳理清楚spring原先对这个bean注册list的使用

如:排序是否会影响dependsOn等原有机制,还是说其实是原有机制排好序再填进队列的

我们的核心目的是改写顺序,一般中间的顺序通过dependsOn这种机制操作就好了,最优先最不优先我们在1也说了,这里更偏向发散思路。

  • 打补丁咯:实现一个“可指定first or last ”的List类,替代工厂原有的list类型。改动应该集中在预实例化单例bean的地方。

这么改动比较可控大概,因为是对队列前后的补丁。

也多少理解了为什么spring乍一看会看起来“臃肿混乱”各种隐式约定。

我们想改动一个Bean加载顺序,都要考虑很多东西:如和原有加载顺序注解影响,如也想到了这个bean如果正好被PostProcessor引用,进而提前加载,那怎么办?要报错吗?其实殊途同归我们也会和spring做出一样的处理,吞掉并提示出类似is not eligible ……