Spring/Spring Boot中@Autowired能否注入@Bean声明的Bean
问题1:@Bean声明的Bean是否支持@Autowired注入
完全支持。@Bean注解声明的Bean和@Component/@Service等类注解标注生成的Bean,在Spring容器中没有本质区别,只要满足类型匹配、Qualifier名称对应,就可以被@Autowired正常注入,框架本身没有任何限制。
你之前给实现类加@Service、移除@Bean方法后注入正常,本质上只是换了一种Bean的注册方式,和@Bean注册的Bean注入规则完全一致。
问题2:当前代码循环依赖的产生原因
你遇到的循环依赖完全是代码写法导致的,和@Bean能不能被注入没有关系,初始化链路如下:
- 你的启动类
SpringBootTestApplication被@SpringBootApplication标注(自带@Configuration元注解),本身就是容器需要初始化的一个配置类Bean - 容器初始化这个配置类Bean时,发现它有字段注入的
ServiceCaller依赖,于是暂停配置类的初始化,转而去创建ServiceCaller实例 - 创建
ServiceCaller实例时,又发现它需要注入名为TestServiceInterfaceImplBean的TestServiceInterface类型Bean - 这个Bean是定义在
SpringBootTestApplication配置类里的@Bean方法,要执行这个方法生成对象,前提是SpringBootTestApplication这个配置类已经完成初始化 - 此时链路绕回起点:配置类没初始化完→拿不到ServiceCaller→ServiceCaller没初始化完→拿不到@Bean定义的TestService实例→拿不到TestService实例→配置类没法完成初始化,形成闭环循环,直接触发报错。
你之前把@Bean方法删掉、给实现类加@Service时不会报错,是因为这时候TestServiceInterfaceImpl是组件扫描直接识别的独立Bean,不需要依赖配置类的方法生成,初始化ServiceCaller时可以直接创建这个实现类实例,链路不会绕回未初始化完成的配置类,自然不会有循环。
额外说明:你main方法里手动创建AnnotationConfigApplicationContext的代码是多余的,SpringApplication.run本身就会创建并初始化容器,重复创建容器会导致不必要的资源浪费和初始化逻辑混乱,建议删掉。
问题3:修复方案
- 方案1(推荐,符合Spring设计规范):不要在启动类/根配置类里写业务Bean的字段注入。启动类只保留启动逻辑,把
ServiceCaller的注入和使用逻辑移到单独的业务组件或独立配置类中,从根源切断循环链路。
修正后的启动类代码:@SpringBootApplication public class SpringBootTestApplication { @Bean(name = "TestServiceInterfaceImplBean") TestServiceInterface getTestService() { return new TestServiceInterfaceImpl(); } public static void main(String[] args) { SpringApplication.run(SpringBootTestApplication.class, args); } } - 方案2:如果确实需要在启动类中持有
ServiceCaller实例,把字段注入改成构造器注入,同时给依赖加@Lazy注解实现延迟加载,打破初始化的闭环:@SpringBootApplication public class SpringBootTestApplication { private final ServiceCaller serviceCaller; @Bean(name = "TestServiceInterfaceImplBean") TestServiceInterface getTestService() { return new TestServiceInterfaceImpl(); } public SpringBootTestApplication(@Lazy ServiceCaller serviceCaller) { this.serviceCaller = serviceCaller; } public static void main(String[] args) { SpringApplication.run(SpringBootTestApplication.class, args); } } - 方案3(不推荐,仅做临时兼容):在application配置文件中添加配置
spring.main.allow-circular-references=true,开启Spring默认关闭的循环依赖自动兜底机制。但这种方式会掩盖代码设计的不合理性,后续版本迭代很容易引发更难排查的问题,非紧急情况不建议使用。
内容的提问来源于stack exchange,提问作者SPL
相关产品推荐
相关产品推荐

