Spring Bean依赖未决定@Bean方法执行顺序的底层机制问询
@Bean方法执行顺序异常现象底层解释
结论先行
你观察到的执行顺序是断点调试时机和@Configuration类代理机制共同导致的假象,你的猜测不成立:Spring不会传入空实例再后续替换,Bean的实际创建顺序完全遵循依赖关系。
底层逻辑说明
1. @Configuration类的CGLIB代理机制
Spring对标注了@Configuration的类会生成CGLIB动态代理子类,代理类会拦截所有@Bean方法的调用:
- 第一次调用目标
@Bean方法时,执行方法本体创建Bean实例,存入单例池 - 后续所有对该方法的调用,直接返回单例池中的实例,不会重复执行方法本体
2. 实际Bean创建流程完全遵循依赖关系
你的示例中transactionManager依赖myDataSource,实际执行顺序必然是:
- Spring触发
transactionManager的Bean创建流程,解析到依赖@Qualifier("myDataSource") DataSource - Spring去单例池查找
myDataSource不存在,触发myDataSource的创建流程,执行dataSource()方法得到实例 - 把初始化完成的
myDataSource实例作为参数,调用transactionManager()方法完成Bean创建
3. 你观察到异常现象的原因
你打的断点落在原始配置类的方法入口,而非代理类的执行逻辑:
- CGLIB代理类在调用原始类的方法前,会先完成依赖解析、依赖Bean创建、参数赋值的前置流程
- 你在原始方法入口断点触发时,代理类的参数赋值逻辑还未执行,此时看到的参数是临时的空值,不是最终传入方法的实际参数
- 等断点继续往下走,代理类会把已经创建好的
dataSource实例赋值给参数,方法实际业务逻辑执行时用的是完整初始化的实例
多数据源场景的关联
你觉得和多数据源有关,是因为多数据源场景下Spring需要解析更多的候选Bean,代理类的前置依赖解析流程耗时更长,在原始方法入口断点停留时,更容易观察到参数未赋值的临时状态,本质和多数据源没有直接绑定关系。
验证方法
你可以在两个@Bean方法的业务逻辑第一行加打印日志,不要依赖断点的入口快照:
@Configuration public class config { @Bean (name = "myDataSource") public DataSource dataSource() { System.out.println("=== dataSource方法执行 ==="); return new HikariDataSource(); } @Bean public TransactionManager transactionManager(@Qualifier("myDataSource") DataSource dataSource) { System.out.println("=== transactionManager方法执行,dataSource是否为空:" + Objects.isNull(dataSource)); return new TransactionManager(dataSource); } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) { System.out.println("=== sqlSessionFactory方法执行,dataSource是否为空:" + Objects.isNull(dataSource)); // 其他逻辑 } }
日志输出顺序永远是dataSource先执行,后续两个方法执行时dataSource都不为空,完全符合依赖顺序。
内容的提问来源于stack exchange,提问作者J Freebird
相关产品推荐
相关产品推荐

