Spring配置类自引用:@Autowired字段替代方案的实现困惑
尝试在同一配置类中注入@Bean方法的返回结果,实际上也是一种自引用场景。**要么在实际需要的方法签名中延迟解析此类引用(而非配置类中的@Autowired字段),要么将受影响的@Bean方法声明为静态方法,使其与所属配置类实例及其生命周期解耦。**否则,此类Bean只会在回退阶段被考虑,此时其他配置类中的匹配Bean会被选为主要候选(如果存在)。
我的理解验证
自引用指的是同一配置类中Bean A调用Bean B,或是将其他Bean作为参数的情况,对吗?
示例代码
配置类
@Configuration public class JavaConfig { @Bean Course course() { Course course = new Course(); return course; } @Bean Teacher teacher(Course course) { // 自引用场景 Teacher teacher = new Teacher(); Course course1 = course(); // 自引用场景 System.out.println(course); teacher.setCourse(course); return teacher; } @Bean String[] courseList() { String[] cs = {"OS", "Network"}; return cs; } }
实体类
public class Course { @Resource(name = "courseList") private String[] courseList; } public class Teacher { private Course course; public void setCourse(Course course) { this.course = course; } @Override public String toString() { return "Teacher{" + "course=" + course + '}'; } }
解决方案解析
1. 将受影响的@Bean方法声明为静态方法
这个思路是正确的。Spring会用CGLIB代理@Configuration类,静态@Bean方法不会被代理拦截,会直接调用方法生成实例,彻底避免自引用带来的生命周期耦合问题。
修改后的配置类示例:
@Configuration public class JavaConfig { @Bean static Course course() { // 添加static修饰符 Course course = new Course(); return course; } // 其余代码不变 }
2. 在实际需要的方法签名中延迟解析此类引用(而非配置类中的@Autowired字段)
这里的核心是别在配置类的成员字段上用@Autowired注入同配置类的Bean,而是把依赖Bean作为目标@Bean方法的参数,Spring会自动帮你延迟解析这个依赖,绕开自引用的代理歧义问题。
错误示例(不推荐)
在配置类内用@Autowired字段注入同配置类的Bean,属于容易出问题的自引用方式:
@Configuration public class JavaConfig { // 错误示范:配置类内用@Autowired字段注入同配置类的Bean @Autowired private Course course; @Bean Course course() { return new Course(); } @Bean Teacher teacher() { Teacher teacher = new Teacher(); teacher.setCourse(this.course); return teacher; } }
正确示例(推荐)
直接把依赖Bean作为@Bean方法的参数,这就是文档说的“在实际需要的方法签名中延迟解析”:
@Configuration public class JavaConfig { @Bean Course course() { return new Course(); } // 正确示范:把Course作为teacher方法的参数,Spring自动处理依赖注入 @Bean Teacher teacher(Course course) { Teacher teacher = new Teacher(); teacher.setCourse(course); return teacher; } }
这么做的原因是:当你把依赖Bean作为@Bean方法的参数时,Spring会在初始化这个Bean时,从容器中获取对应的实例(而非直接调用配置类的方法),既避免了CGLIB代理带来的自引用问题,也不需要额外加@Lazy。文档里强调“而非配置类中的@Autowired字段”,就是明确让你放弃配置类字段注入的方式,改用方法参数注入。
内容的提问来源于stack exchange,提问作者OnlyWick

