因为业务需求,mentor想要某些 bean 启动时优先加载,将数据存入缓存,便问我,“能不能调下Bean初始化顺序?”,于是便有了这篇文章
目前一共有两个 service ,每个 service 都有一个 init 方法,打印bean创建时机,正常状态打印结果如下:
这是第一个想到的方法,我们给每个service上加上@Order,让他们倒序创建
代码:
结果:
嗯?不是数字越低优先级越高吗,结果怎么还是 1 -> 2?相信眼尖的人已经看出来了,我在开头埋了个坑,用 @PostConstruct 作初始化操作
@PostConstruct 方法的执行顺序是由 Spring 容器在 bean 初始化过程中自动管理的,与 @Order 注解无关。
从 SpringBoot 的 run 源码角度来看
优点 :简单明了,适用于需要简单控制初始化顺序的场景。
缺点:只适用于具有顺序的Bean,无法处理复杂依赖关系,遇到如 @PostConstruct 会失效
SmartInitializingSingleton 用于在容器完成所有单例 bean 的初始化后执行一些额外的初始化工作。用这个接口应该能保证 FirstService 后创建了吧
代码:
结果:
还是不行,@PostConstruct 的东西还是先创建了,不过起码保证了 FirstService 的 afterSingletonsInstantiated 方法是所有单例 Bean 初始化之后执行的。
不过毫无疑问,被驳回了,还说这要是有三个或多个 Bean 有这业务怎么办
优点 :确保所有单例bean都初始化,适合在所有Bean创建后执行全局初始化逻辑。
缺点:不适合控制特定Bean之间的初始化顺序。
既然加载顺序不行,还要有多个 Bean ,那就从 Bean 间的依赖入手嘛
代码:
结果:
不出意外的成功了,但是mentor嫌耦合性太高,一处改了处处改,后期项目大了找不到不方便维护
优点 :简单明了,适用于明确的依赖关系。
缺点:依赖关系硬编码在配置类中,灵活性较低,耦合性高。
那好嘛,那自定义呗
代码
在 META-INF 的 spring.factories 加上配置ini
代码解读复制代码org.springframework.context.ApplicationContextInitializer=\com.hhh.init.MyBeanInit
解释:
BeanFactoryPostProcessor
运行之前执行,允许我们注册或修改 BeanDefinition
BeanFactoryPostProcessor
或其他配置。ThirdService
和 SecondService
类,然后,将这些 Bean 定义注册到 Spring 容器中,分别命名为 "thirdService"
和 "secondService"
。BeanFactoryPostProcessor
列表中。在容器启动时,postProcessBeanDefinitionRegistry
方法将被调用,从而注册我们在上面定义的 Bean。简而言之:自定义 Bean 注册方法,将自己想要优先加载的 Bean 塞进去,再加入上下文中加载
这里我们也可以把 @Component 去掉,因为在自定义初始化类中加载了,不需要被 ComponentScan 再扫描注册一次,以免出现重复注册异常
结果
优点 :灵活性高,可以用于复杂的初始化逻辑。
缺点 :需要手动管理Bean的初始化顺序,代码维护成本较高。