实战指南:四种调整 Spring Bean 初始化顺序的方案

简介: 本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析:1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。

背景

因为业务需求,mentor想要某些 bean 启动时优先加载,将数据存入缓存,便问我,“能不能调下Bean初始化顺序?”,于是便有了这篇文章

结构演示

目前一共有两个 service ,每个 service 都有一个 init 方法,打印bean创建时机,正常状态打印结果如下:

正文

方案一 ( @Order )

这是第一个想到的方法,我们给每个service上加上@Order,让他们倒序创建

代码

结果

嗯?不是数字越低优先级越高吗,结果怎么还是 1 -> 2?相信眼尖的人已经看出来了,我在开头埋了个坑,用 @PostConstruct 作初始化操作

题外话( @PostConstruct 和 @Order 优先级)

  • @PostConstruct 修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次,也就在依赖注入完成后立即调用,bean 初始化阶段执行的。
  • @Order 注解用于设置组件的执行顺序,排序集合或指定某些类型的组件的优先级

@PostConstruct 方法的执行顺序是由 Spring 容器在 bean 初始化过程中自动管理的,与 @Order 注解无关。

SpringBootrun 源码角度来看

结论

优点 :简单明了,适用于需要简单控制初始化顺序的场景。

缺点:只适用于具有顺序的Bean,无法处理复杂依赖关系,遇到如 @PostConstruct 会失效

方案二 ( SmartInitializingSingleton )

SmartInitializingSingleton 用于在容器完成所有单例 bean 的初始化后执行一些额外的初始化工作。用这个接口应该能保证 FirstService 后创建了吧

代码

结果

还是不行@PostConstruct 的东西还是先创建了,不过起码保证了 FirstServiceafterSingletonsInstantiated 方法是所有单例 Bean 初始化之后执行的。

不过毫无疑问,被驳回了,还说这要是有三个或多个 Bean 有这业务怎么办

结论

优点 :确保所有单例bean都初始化,适合在所有Bean创建后执行全局初始化逻辑。

缺点:不适合控制特定Bean之间的初始化顺序。

方案三 ( @DependsOn )

既然加载顺序不行,还要有多个 Bean ,那就从 Bean 间的依赖入手嘛

代码

结果

不出意外的成功了,但是mentor嫌耦合性太高,一处改了处处改,后期项目大了找不到不方便维护

结论

优点 :简单明了,适用于明确的依赖关系。

缺点:依赖关系硬编码在配置类中,灵活性较低,耦合性高。

方案四 ( 自定义 Bean 初始化类 )

那好嘛,那自定义呗

代码

在 META-INF 的 spring.factories 加上配置

ini

代码解读

复制代码

org.springframework.context.ApplicationContextInitializer=\com.hhh.init.MyBeanInit 

解释

  1. 该自定义类 MyBeanInit 分别继承了 BeanDefinitionRegistryPostProcessorApplicationContextInitializer ,重写其内部方法
  • BeanDefinitionRegistryPostProcessor提前注册或修改 Bean 定义,在所有其他 BeanFactoryPostProcessor 运行之前执行,允许我们注册或修改 BeanDefinition
  • ApplicationContextInitializer初始化应用上下文,在应用上下文刷新之前调用,可以动态地为应用上下文添加属性、BeanFactoryPostProcessor 或其他配置。
  1. postProcessBeanDefinitionRegistry 方法中,使用 BeanDefinitionBuilder 创建了两个 AbstractBeanDefinition 实例,分别对应 ThirdServiceSecondService 类,然后,将这些 Bean 定义注册到 Spring 容器中,分别命名为 "thirdService""secondService"
  2. initialize 方法中,将当前的 BeanDefinitionRegistryPostProcessor 实例( MyBeanInit 自身)添加到应用上下文的 BeanFactoryPostProcessor 列表中。在容器启动时,postProcessBeanDefinitionRegistry 方法将被调用,从而注册我们在上面定义的 Bean。

简而言之:自定义 Bean 注册方法,将自己想要优先加载的 Bean 塞进去,再加入上下文中加载

这里我们也可以把 @Component 去掉,因为在自定义初始化类中加载了,不需要被 ComponentScan 再扫描注册一次,以免出现重复注册异常

结果

结论

优点 :灵活性高,可以用于复杂的初始化逻辑。

缺点 :需要手动管理Bean的初始化顺序,代码维护成本较高。


转载来源:https://juejin.cn/post/7380663251632586767

相关文章
|
9月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
625 26
|
7月前
|
安全 Java 数据库
Spring Security 实战指南:从入门到精通
本文详细介绍了Spring Security在Java Web项目中的应用,涵盖登录、权限控制与安全防护等功能。通过Filter Chain过滤器链实现请求拦截与认证授权,核心组件包括AuthenticationProvider和UserDetailsService,负责用户信息加载与密码验证。文章还解析了项目结构,如SecurityConfig配置类、User实体类及自定义登录逻辑,并探讨了Method-Level Security、CSRF防护、Remember-Me等进阶功能。最后总结了Spring Security的核心机制与常见配置,帮助开发者构建健壮的安全系统。
429 0
|
6月前
|
人工智能 负载均衡 Java
Spring AI Alibaba 发布企业级 MCP 分布式部署方案
本文介绍了Spring AI Alibaba MCP的开发与应用,旨在解决企业级AI Agent在分布式环境下的部署和动态更新问题。通过集成Nacos,Spring AI Alibaba实现了流量负载均衡及节点变更动态感知等功能。开发者可方便地将企业内部业务系统发布为MCP服务或开发自己的AI Agent。文章详细描述了如何通过代理应用接入存量业务系统,以及全新MCP服务的开发流程,并提供了完整的配置示例和源码链接。未来,Spring AI Alibaba计划结合Nacos3的mcp-registry与mcp-router能力,进一步优化Agent开发体验。
2414 15
|
11月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
286 12
|
11月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
381 12
|
11月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
345 6
|
11月前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
472 4
|
11月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
268 1
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
859 0
下一篇