使用@Scheduled和@EnableScheduling,但给出NoSuchBeanDefinitionException

2022-09-01 09:36:36

我按照非常简单的在线示例在春季设置了cron作业,但我每次都会在我的Tomcat启动日志中收到此错误:

2015-05-25 00:32:58 DEBUG ScheduledAnnotationBeanPostProcessor:191 - 
Could not find default TaskScheduler bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No 
qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined

2015-05-25 00:32:58 DEBUG ScheduledAnnotationBeanPostProcessor:202 - Could not    
find default ScheduledExecutorService bean
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying    
bean of type [org.springframework.scheduling.TaskScheduler] is defined

以及用于实现 cron 的 2 个 java 类:

  • @Configuration类:

    @Configuration
    @EnableScheduling
    public class ClearTokenStoreCronEnable {    
      final static Logger log =   
      LoggerFactory.getLogger(ClearTokenStoreCronEnable.class);
      private @Autowired TokenStoreRepository tokenStoreRepository; 
    }
    
  • 和 Cron 工作类:

    @Service
    public class ClearTokenStoreWorkerService {
    
        final static Logger log = LoggerFactory.getLogger(ClearTokenStoreWorkerService.class);
        private @Autowired TokenStoreRepository tokenStoreRepository;
    
        //@Scheduled(fixedDelay=5000)
        //run daily at midnight
        @Scheduled(cron = "0 0 * * * *")
        public void tokenStoreTable() {
            log.debug("tokenstore table truncated - start");
            tokenStoreRepository.deleteAll();
            log.debug("tokenstore table truncated - end");
        }
    }
    

顺便说一句,cron 作业在午夜运行,但似乎在其他时间也随机运行。不确定这是一个错误还是我的cron表达式是错误的:@Scheduled(cron = "0 0 * * * *")

我现在主要担心的是,为什么我会收到 ScheduledAnnotationBeanPostProcessor 错误?它正在寻找一个 TaskScheduler 和 ScheduledExectorService。我只需要每天发射一次。我没有进行任何并发处理或需要多个线程的地方。最终,这些错误是有害的还是我需要修复它们?


答案 1

根据异常信息,配置应该定义而不是“执行器”Could not find default TaskScheduler beanTaskScheduler

@Configuration
public class AppContext extends WebMvcConfigurationSupport {
    @Bean
    public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();
    }

    // Of course , you can define the Executor too
    @Bean
    public Executor taskExecutor() {
        return new SimpleAsyncTaskExecutor();
   }
}

答案 2

编辑:最好的答案在这里,它涉及创建一个执行器:

@Configuration
@EnableAsync
public class AppContext extends WebMvcConfigurationSupport {
    @Bean
    public Executor taskExecutor() {
        return new SimpleAsyncTaskExecutor();
    }
}

上一个(仍然有效):

NoSuchBeanDefinitionException 记录有 DEBUG 严重性,可以安全地忽略。如果你看一下 ScheduledAnnotationBeanPostProcessor 的源代码,你会看到它首先尝试获取一个 TaskScheduler,然后是 ScheduledExecutorService,然后它一直在“回退到默认调度程序”:

    if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
        Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
        try {
            // Search for TaskScheduler bean...
            this.registrar.setScheduler(this.beanFactory.getBean(TaskScheduler.class));
        }
        catch (NoUniqueBeanDefinitionException ex) {
            throw new IllegalStateException("More than one TaskScheduler exists within the context. " +
                    "Remove all but one of the beans; or implement the SchedulingConfigurer interface and call " +
                    "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback.", ex);
        }
        catch (NoSuchBeanDefinitionException ex) {
            logger.debug("Could not find default TaskScheduler bean", ex);
            // Search for ScheduledExecutorService bean next...
            try {
                this.registrar.setScheduler(this.beanFactory.getBean(ScheduledExecutorService.class));
            }
            catch (NoUniqueBeanDefinitionException ex2) {
                throw new IllegalStateException("More than one ScheduledExecutorService exists within the context. " +
                        "Remove all but one of the beans; or implement the SchedulingConfigurer interface and call " +
                        "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback.", ex);
            }
            catch (NoSuchBeanDefinitionException ex2) {
                logger.debug("Could not find default ScheduledExecutorService bean", ex);
                // Giving up -> falling back to default scheduler within the registrar...
            }
        }
    }

您可以通过在 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor 上设置至少 INFO 严重性来删除异常,例如

<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>

使用日志备份时。

cron 表达式有六个字段:

second (0-59), minute (0-59), hour (0-23, 0 = midnight), day (1-31), month (1-12), weekday (1-7, 1 = Sunday)

语法可以在石英文档中找到。我不确定“?”字符,因为,尽管页面说

“?”字符可用于月中某一天和星期几字段。它用于指定“无特定值”。当您需要在两个字段中的一个字段中指定某些内容,而不是在另一个字段中指定某些内容时,这很有用。

该页面上的示例实际使用 ?即使另一个字段是 *。恕我直言,所有方法都应该使用 *,因此为了在每个午夜执行,表达式应该是

0 0 0 * * *

推荐