Spring 定时任务 No qualifying bean of type TaskScheduler available 及 Could not find default TaskScheduler bean异常处理

  |   0 评论   |   0 浏览

最近使用 Spring + SpringMvc + Quartz 的系统中,使用@annotation 注解方式, 直接在类的方法上使用@Scheduled(cron=”0 /5 * * ?”)来实现定时任务,在使用 debug 日志级别时,启动提示 Could not find default TaskScheduler bean 异常:

10:44:18.816 [main] DEBUG org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor - Could not find default TaskScheduler bean

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.scheduling.TaskScheduler' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:996)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:994)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:285)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:226)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:203)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:97)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
	at org.springframework.context.support.AbstractApplicationContext.__refresh(AbstractApplicationContext.java:546)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:41010)
	at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)
	at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)
	at org.springframework.web.servlet.FrameworkServlet.jrInitWebApplicationContext(FrameworkServlet.java:40002)
	at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)
	at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:171)
	at javax.servlet.GenericServlet.init(GenericServlet.java:158)
	at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1123)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1078)
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:971)
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4849)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5165)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1382)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1372)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:907)
	at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:831)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1382)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1372)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:907)
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:423)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:933)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:637)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.__invoke(DelegatingMethodAccessorImpl.java:43)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45009)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45012)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:350)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:492)
10:44:18.823 [main] DEBUG org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor - Could not find default ScheduledExecutorService bean

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.concurrent.ScheduledExecutorService' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:996)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:994)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:285)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:247)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:203)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:97)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
	at org.springframework.context.support.AbstractApplicationContext.__refresh(AbstractApplicationContext.java:546)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:41010)
	at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)
	at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)
	at org.springframework.web.servlet.FrameworkServlet.jrInitWebApplicationContext(FrameworkServlet.java:40002)
	at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)
	at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:171)
	at javax.servlet.GenericServlet.init(GenericServlet.java:158)
	at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1123)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1078)
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:971)
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4849)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5165)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1382)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1372)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:907)
	at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:831)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1382)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1372)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:907)
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:423)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:933)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:637)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.__invoke(DelegatingMethodAccessorImpl.java:43)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45009)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45012)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:350)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:492)
10:44:18.823 [main] INFO org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor - No TaskScheduler/ScheduledExecutorService bean found for scheduled processing

很困惑,配置都没有问题啊?通过在 Stack Overflo 辛苦的寻找才发现其实是定时任务框架的一个机制,原来在 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.inishRegistration():这个方法中,是这样处理的:

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.setTaskScheduler(this.beanFactory.getBean(TaskScheduler.class));
    }
    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 (NoSuchBeanDefinitionException ex2) {
            logger.debug("Could not find default ScheduledExecutorService bean", ex);
            // Giving up -> falling back to default scheduler within the registrar...
        }
    }
}

上面代码中,程序通过 beanfactory.getbean 方法找到在 Spring 中注册的调度器, 如果 ScheduledExecutorService 没有找到,就使用默认的调度器。所以,这个过程中如果没有找到 ScheduledExecutorService,就会在 debug 级别的日志输出一个异常:

logger.debug("Could not find default TaskScheduler bean", ex); 

当然,这个你所看到的异常并不影响应用程序运行,如果你不想看到这个异常,就可以通过提升 org.springframework.scheduling 这个包下日志级别来屏蔽这个不合理的异常:
logback & log4j XML:

<logger name="org.springframework.scheduling">
    <level value="info" />
</logger> 

log4j.properties

log4j.logger.org.springframework.scheduling=INFO

当然,你也可以通过配置上下文:

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

或者配置 spring-mvc.xml 文件:

<task:executor id="executor" pool-size="100"/> 
<task:scheduler id="scheduler" pool-size="100"/>
<task:annotation-driven scheduler="scheduler" executor="executor" proxy-target-class="true"/>

参见:https://stackoverflow.com/questions/31816365/spring-async-issue-when-upgrading-from-4-2-0-rc3-to-4-2-0-release/31820129#31820129