You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:03:09