@DependsOn 是 Spring 框架中用于显式声明 Bean 之间依赖关系的核心注解,通过强制指定被依赖 Bean 的初始化顺序,解决因依赖关系不明确导致的初始化问题(如未初始化的依赖被提前使用)。以下从注解定义、源码解析、核心功能、使用场景及注意事项展开详细说明。
一、@DependsOn 注解的定义与源码解析
@DependsOn 位于 org.springframework.context.annotation 包中,其源码定义如下(简化版):
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
/**
* 依赖的 Bean 名称(支持多个,用逗号分隔)
*/
String[] value() default {};
}
关键特性:
- 标记在
@Configuration配置类或@Bean方法上,声明当前 Bean 依赖的其他 Bean。 - 被依赖的 Bean 会在当前 Bean 之前初始化(确保当前 Bean 使用时依赖已就绪)。
二、核心功能:控制 Bean 的初始化顺序
Spring 容器的默认行为是根据 Bean 的依赖关系自动推导初始化顺序(如 A 依赖 B,则 B 先初始化)。但当依赖关系复杂或隐式时(如通过方法调用间接依赖),Spring 可能无法正确推导顺序,导致初始化错误。@DependsOn 的核心作用是显式声明依赖顺序,强制被依赖的 Bean 先于当前 Bean 初始化。
1. 工作流程
Spring 启动时,ConfigurationClassParser 会扫描所有 @Configuration 类和 @Bean 方法上的 @DependsOn 注解,并通过 DependsOnAnnotationBeanPostProcessor 调整 Bean 的初始化顺序。具体流程如下:
- 解析
@DependsOn注解:获取当前 Bean 依赖的 Bean 名称列表。 - 验证依赖存在性:检查被依赖的 Bean 是否已声明(否则抛
NoSuchBeanDefinitionException)。 - 调整初始化顺序:将被依赖的 Bean 标记为“需优先初始化”,确保在当前 Bean 之前完成初始化。
2. 与自动依赖推导的区别
Spring 默认通过以下方式自动推导依赖顺序:
- 构造器注入:若 Bean A 的构造器参数是 Bean B,则 B 先初始化。
@Autowired字段/方法注入:若 Bean A 注入 Bean B,则 B 先初始化。
@DependsOn 适用于以下场景:
- 依赖关系未通过构造器/
@Autowired显式声明(如通过方法调用间接依赖)。 - 需要强制指定顺序(即使自动推导顺序与预期不符)。
三、典型使用场景与示例
1. 显式声明隐式依赖
当 Bean A 通过方法调用间接依赖 Bean B(未通过构造器/@Autowired 注入),Spring 无法自动推导依赖顺序,需用 @DependsOn 显式声明。
示例:
@Configuration
public class ServiceConfig {
// 未直接注入,但 ServiceA 会调用 ServiceB 的方法
@Bean
public ServiceA serviceA() {
return new ServiceA(); // 内部调用 serviceB.doSomething()
}
@Bean
@DependsOn("serviceA") // 错误!ServiceA 依赖 ServiceB,但此处声明反了
public ServiceB serviceB() {
return new ServiceB();
}
}
正确方式:
@Configuration
public class ServiceConfig {
@Bean
@DependsOn("serviceB") // ServiceA 依赖 ServiceB,声明 ServiceB 先初始化
public ServiceA serviceA(ServiceB serviceB) { // 构造器注入 ServiceB(显式依赖)
return new ServiceA(serviceB); // 内部使用 serviceB
}
@Bean
public ServiceB serviceB() {
return new ServiceB();
}
}
2. 有状态 Bean 的初始化顺序
有状态 Bean(如保存用户会话的 UserSessionManager)需要依赖无状态 Bean(如 CacheService),需确保 CacheService 先初始化。
示例:
@Configuration
public class SessionConfig {
@Bean
@DependsOn("cacheService") // UserSessionManager 依赖 CacheService
public UserSessionManager userSessionManager(CacheService cacheService) {
return new UserSessionManager(cacheService); // 注入 CacheService
}
@Bean
public CacheService cacheService() {
return new RedisCacheService(); // 无状态 Bean
}
}
3. 第三方库 Bean 的初始化顺序
集成第三方库时,需确保库的初始化 Bean 先于业务 Bean 执行(如 MyBatis 的 SqlSessionFactory 需先于 Mapper 初始化)。
示例:
@Configuration
public class MyBatisConfig {
@Bean
@DependsOn("dataSource") // SqlSessionFactory 依赖 DataSource
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}
四、源码实现细节与关键类
1. DependsOnAnnotationBeanPostProcessor
Spring 处理 @DependsOn 的核心类,继承自 InstantiationAwareBeanPostProcessorAdapter,负责调整 Bean 的初始化顺序。其关键逻辑如下:
(1)扫描 @DependsOn 注解
在解析 @Configuration 类或 @Bean 方法时,扫描 @DependsOn 注解,获取依赖的 Bean 名称列表。
(2)注册依赖关系
将当前 Bean 与依赖的 Bean 建立依赖关系(通过 BeanDefinition 的 setDependsOn 方法),确保被依赖的 Bean 先初始化。
2. BeanDefinition 的 dependsOn 属性
Spring 的 BeanDefinition 接口有一个 dependsOn 方法,用于声明当前 Bean 依赖的其他 Bean 名称。DependsOnAnnotationBeanPostProcessor 会将该属性设置为 @DependsOn 注解的 value,从而触发初始化顺序的调整。
五、注意事项与常见问题
1. 循环依赖的处理
@DependsOn 无法解决循环依赖(如 A 依赖 B,B 依赖 A)。此时 Spring 会抛出 BeanCurrentlyInCreationException,需通过以下方式解决:
- 使用
@Lazy延迟初始化(仅适用于构造器注入)。 - 改为通过方法调用获取依赖(非构造器/
@Autowired注入)。
2. 依赖的 Bean 不存在
若 @DependsOn 声明的依赖 Bean 未在容器中注册,Spring 会抛出 NoSuchBeanDefinitionException。需确保依赖的 Bean 已通过 @Bean、@Component 或 @ConfigurationProperties 注册。
3. 与 @Conditional 的协同
@DependsOn 与 @Conditional 注解(如 @ConditionalOnProperty)可结合使用,实现条件化的依赖顺序控制。例如:仅当某个属性为 true 时,声明依赖关系。
4. 性能影响
@DependsOn 的处理在 Spring 启动时完成(调整 Bean 定义顺序),对运行时性能无影响。
5. 优先使用构造器注入
若依赖关系明确,优先通过构造器注入声明依赖(Spring 自动推导顺序),@DependsOn 仅作为补充(如隐式依赖场景)。
六、总结
@DependsOn 是 Spring 中显式控制 Bean 初始化顺序的核心注解,适用于依赖关系隐式或需要强制指定顺序的场景。其核心机制依赖 DependsOnAnnotationBeanPostProcessor 和 BeanDefinition 的 dependsOn 属性,确保被依赖的 Bean 先于当前 Bean 初始化。理解其源码和使用场景,有助于开发者编写更健壮、可维护的 Spring 应用。
759

被折叠的 条评论
为什么被折叠?



