BeanCurrentlyInCreationException问题求助:@Lazy与@Bean尝试无效
解决BeanCurrentlyInCreationException循环依赖问题
问题描述
我搜了好多相关帖子,都没找到解决BeanCurrentlyInCreationException异常的合适办法。创建TaskScheduler的时候,我试过用@Lazy和@Bean注解,但两种方式都不管用。
MyDireConfig.java
@Slf4j @Configuration public class MyDireConfig implements InitializingBean { @Value("${testdir.retain-backup-files:true}") boolean retainBackupFiles; @Value("${testdir.backup-directory}") String backupDirectory; @Value("${testdir.error-directory}") String errorDirectory; @Value("${camel.springboot.auto-startup:true}") String camelSpringbootAutoStartup; @Value("${camel.springboot.main-run-controller:true}") String camelSpringbootMainRunController; @Autowired (required=false) MyDireCleaner myDireCleaner; @Override public void afterPropertiesSet() throws Exception { if (cleanInterval < 300000L) cleanInterval = 300000L; if (retainBackupFiles && maxBackupFileAge > 0) { log.info("Max backup file age: " + maxBackupFileAge + " day(s)"); Calendar c = Calendar.getInstance(); c.add(Calendar.DATE, -maxBackupFileAge); taskScheduler().scheduleWithFixedDelay(() -> {myDireCleaner.deleteExpiredPaths(Paths.get(backupDirectory), c.getTime());}, new Date(System.currentTimeMillis() + 10000L), cleanInterval); } } public boolean retainBackupFiles() { return retainBackupFiles; } public String getBackupDirectory(String dirId) { return Paths.get(backupDirectory, dirId).toString().replace("\\", "/"); } public String getErrorDirectory(String dirId) { return Paths.get(errorDirectory, dirId).toString().replace("\\", "/"); } @Bean public TaskScheduler taskScheduler() { return new ConcurrentTaskScheduler(); } }
错误日志
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyDireConfig' defined in URL [jar:file:/C:/Program%20Files/test/myprogram/lib/myapp.jar!/BOOT-INF/classes!/com/test/myprogram/MyDireConfig.class]: Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'MyDireConfig': *Requested bean is currently in creation: Is there an unresolvable circular reference?* at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
问题原因
这个循环引用的核心原因是:你在MyDireConfig的初始化方法afterPropertiesSet()中直接调用了带有@Bean注解的taskScheduler()方法。Spring在处理@Bean方法时,会尝试获取当前配置类MyDireConfig的实例来生成Bean,但此时MyDireConfig本身正处于初始化流程中(正在执行afterPropertiesSet),从而触发了循环依赖报错。
解决方案
方案一:注入TaskScheduler替代直接调用方法
将TaskScheduler作为依赖注入到配置类中,而非直接调用@Bean标注的方法:
@Slf4j @Configuration public class MyDireConfig implements InitializingBean { // ... 原有属性保持不变 @Autowired(required = false) MyDireCleaner myDireCleaner; // 注入TaskScheduler实例 @Autowired private TaskScheduler taskScheduler; @Override public void afterPropertiesSet() throws Exception { if (cleanInterval < 300000L) cleanInterval = 300000L; if (retainBackupFiles && maxBackupFileAge > 0) { log.info("Max backup file age: " + maxBackupFileAge + " day(s)"); Calendar c = Calendar.getInstance(); c.add(Calendar.DATE, -maxBackupFileAge); // 使用注入的taskScheduler taskScheduler.scheduleWithFixedDelay(() -> {myDireCleaner.deleteExpiredPaths(Paths.get(backupDirectory), c.getTime());}, new Date(System.currentTimeMillis() + 10000L), cleanInterval); } } // ... 原有方法保持不变 @Bean public TaskScheduler taskScheduler() { return new ConcurrentTaskScheduler(); } }
方案二:将TaskScheduler的Bean定义移至独立配置类
把TaskScheduler的@Bean方法单独放到另一个配置类中,避免和当前配置类产生耦合:
@Configuration public class TaskSchedulerConfig { @Bean public TaskScheduler taskScheduler() { return new ConcurrentTaskScheduler(); } }
之后在MyDireConfig中注入这个TaskScheduler,用法和方案一一致。
方案三:通过ApplicationContext获取Bean(应急方案,不推荐)
如果上述方案无法快速落地,可以实现ApplicationContextAware接口,在初始化方法中获取TaskScheduler实例:
@Slf4j @Configuration public class MyDireConfig implements InitializingBean, ApplicationContextAware { // ... 原有属性保持不变 private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void afterPropertiesSet() throws Exception { if (cleanInterval < 300000L) cleanInterval = 300000L; if (retainBackupFiles && maxBackupFileAge > 0) { log.info("Max backup file age: " + maxBackupFileAge + " day(s)"); Calendar c = Calendar.getInstance(); c.add(Calendar.DATE, -maxBackupFileAge); // 从ApplicationContext中获取TaskScheduler TaskScheduler taskScheduler = applicationContext.getBean(TaskScheduler.class); taskScheduler.scheduleWithFixedDelay(() -> {myDireCleaner.deleteExpiredPaths(Paths.get(backupDirectory), c.getTime());}, new Date(System.currentTimeMillis() + 10000L), cleanInterval); } } // ... 原有方法保持不变 @Bean public TaskScheduler taskScheduler() { return new ConcurrentTaskScheduler(); } }
为什么@Lazy没用?
@Lazy注解的作用是延迟Bean的初始化,但你是在当前Bean的初始化方法中触发了自身Bean的获取请求,此时MyDireConfig已经处于创建流程中,@Lazy无法打破这个循环依赖关系。
内容的提问来源于stack exchange,提问作者JDGuide
相关产品推荐
相关产品推荐

