Spring Boot + Quartz:“请求的 bean 当前正在创建中:是不是存在无法解析的循环引用?”

Posted

技术标签:

【中文标题】Spring Boot + Quartz:“请求的 bean 当前正在创建中:是不是存在无法解析的循环引用?”【英文标题】:Spring Boot + Quartz: "Requested bean is currently in creation: Is there an unresolvable circular reference?"Spring Boot + Quartz:“请求的 bean 当前正在创建中:是否存在无法解析的循环引用?” 【发布时间】:2017-05-29 10:08:05 【问题描述】:

我已经按照本教程 (spring-boot-quartz-demo) 在我的 Spring Boot 应用程序中使用 Quartz Scheduler 实现了一个调度程序例程,并为我的目的进行了一些修改。

例如,我的工作服务必须能够列出数据库中的所有对象及其子对象,设置新值并最终更新。所有这些都必须是事务性的。

由于某种原因,MyJob 类不允许在其中声明事务方法,因此我通过注入具有事务方法的新服务类来解决此问题。

这项工作运行良好,但每次我运行应用程序时,它都会给我一些警告消息:

[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
[main] WARN  o.s.b.f.s.DefaultListableBeanFactory - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testJobBeanTrigger': Requested bean is currently in creation: Is there an unresolvable circular reference?

我减少了警告消息: @DependsOn("testJobBean")

我注意到作业类中的自动装配服务导致它,但为什么呢?我必须做些什么才能摆脱此警告消息?

欢迎解决如何在作业类中声明@Transacional 方法!

QuartzConfig.java

@Configuration
@ConditionalOnProperty(name = "quartz.enabled")
public class QuartzConfig 

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    List<Trigger> triggers;

    @Bean
    public JobFactory jobFactory() 
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws IOException 
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setOverwriteExistingJobs(true);
        factory.setDataSource(dataSource);
        factory.setTransactionManager(transactionManager);
        factory.setJobFactory(jobFactory);
        factory.setQuartzProperties(quartzProperties());

        if (triggers != null && !triggers.isEmpty()) 
            factory.setTriggers(((Trigger[]) triggers.toArray(new Trigger[triggers.size()])));
        

        return factory;
    

    @Bean
    public Properties quartzProperties() throws IOException 
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    

    public static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs) 
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetail);
        factoryBean.setRepeatInterval(pollFrequencyMs);
        factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
        return factoryBean;
    

    public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) 
        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetail);
        factoryBean.setCronExpression(cronExpression);
        factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
        return factoryBean;
    

    public static JobDetailFactoryBean createJobDetail(Class<?> jobClass) 
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(jobClass);
        factoryBean.setDurability(true);
        return factoryBean;
    


AutowiringSpringBeanJobFactory.java

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware 

    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) 
        beanFactory = context.getAutowireCapableBeanFactory();
    

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception 
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    

MyJob.java

@Component
@DisallowConcurrentExecution
public class TestJob implements Job 

    @Autowired
    private TestService service;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException 
        service.execute();
    

    @Bean(name = "testJobBean")
    public JobDetailFactoryBean createJobDetail() 
        return QuartzConfig.createJobDetail(this.getClass());
    

    @DependsOn("testJobBean")
    @Bean(name = "testJobBeanTrigger")
    public CronTriggerFactoryBean createTrigger(@Qualifier("testJobBean") JobDetail jobDetail,
            @Value("$quartz.job.test.cronExpression") String cronExpression) 
        return QuartzConfig.createCronTrigger(jobDetail, cronExpression);
    


MyService.java

@Service
@Slf4j
public class MyService 

    private TestRepository testRepository;

    @Autowired
    public MyService(TestRepository testRepository) 
        this.testRepository = testRepository;
    

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
    public void execute() 
        log.debug("Job has been started");
        List<TestObject> list = testRepository.findAll();
        if (list != null && !list.isEmpty()) 

            System.out.println("\n");
            list.forEach(obj -> 
                System.out.println(
                        "TestObject ID: " + obj.getId() + "\n" + 
                        "SubTestObjects IDs: " + (obj.getSubTestObjects() == null ? "null" : obj.getSubTestObjects().toString()) + 
                        "AnotherSubTestObjects IDs: " + (obj.getAnotherSubTestObjects() == null ? "null" : obj.getAnotherSubTestObjects().toString())
                        );
            );
            System.out.println();

            log.info(list.size() + " test objects found");
         else 
            log.info("No test objects were found");
        
        log.debug("Job has been finished");
    


quartz.properties

#============================================================================
# Configure Main Scheduler Properties
#============================================================================

org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.makeSchedulerThreadDaemon = true

#============================================================================
# Configure ThreadPool
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 1
org.quartz.threadPool.makeThreadsDaemons = true

#============================================================================
# Configure JobStore
#============================================================================

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.useProperties = true
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.clusterCheckinInterval 3600000

【问题讨论】:

【参考方案1】:

看起来问题可能出在createJobDetail 方法中,请考虑以下sn-p:

    @Bean(name = "testJobBean")
    public JobDetailFactoryBean createJobDetail() 
        return QuartzConfig.createJobDetail(this.getClass());
    

    @DependsOn("testJobBean")
    @Bean(name = "testJobBeanTrigger")
    public CronTriggerFactoryBean createTrigger(@Qualifier("testJobBean") JobDetail jobDetail,
            @Value("$quartz.job.test.cronExpression") String cronExpression) 
        return QuartzConfig.createCronTrigger(jobDetail, cronExpression);
    

它在它的实现中使用this,它持有对当前对象的引用。但是,当前对象当时也可能正在创建中,从而导致此错误。我建议将这 2 个移至 Config 类。

另外,使用@DependsOn 不是一个好习惯。

【讨论】:

你说得对,移动这两个 bean 创建方法可以解决这个问题,但我是故意这样做的,因为我想将我的工作与配置隔离开来。

以上是关于Spring Boot + Quartz:“请求的 bean 当前正在创建中:是不是存在无法解析的循环引用?”的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 应用系列 6 -- Spring Boot 2 整合Quartz

170412Spring Boot Quartz介绍

Spring Boot集成Quartz注入Spring管理的类

spring boot + quartz 集群

spring boot整合quartz定时任务案例

spring-boot-starter-quartz集群实践