Java 为什么Spring4在一个上下文中只允许一个TaskScheduler?

Java 为什么Spring4在一个上下文中只允许一个TaskScheduler?,java,spring,Java,Spring,我们有一个SpringWeb应用程序,正在从Spring3.2移植到Spring4。当web应用程序启动时,我们的应用程序将多个子上下文组装到单个运行时上下文中 我们在两个子上下文中使用单独的任务调度器。对于Spring3.2,这工作得很好;使用Spring 4时,我们会收到一个异常,并显示以下消息: java.lang.IllegalStateException: More than one TaskScheduler and/or ScheduledExecutorService exis

我们有一个SpringWeb应用程序,正在从Spring3.2移植到Spring4。当web应用程序启动时,我们的应用程序将多个子上下文组装到单个运行时上下文中

我们在两个子上下文中使用单独的任务调度器。对于Spring3.2,这工作得很好;使用Spring 4时,我们会收到一个异常,并显示以下消息:

java.lang.IllegalStateException: More than one TaskScheduler and/or ScheduledExecutorService  exist within the context. Remove all but one of the beans; or implement the SchedulingConfigurer interface and call ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback. Found the following beans: [commonScheduler, communicationTaskScheduler]
        at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:289) ~[spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:72) ~[spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:98) ~[spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:333) ~[spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:776) ~[spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:485) ~[spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403) ~[spring-web-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) ~[spring-web-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106) ~[spring-web-4.0.1.RELEASE.jar:4.0.1.RELEASE]
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4961) ~[catalina.jar:7.0.50]
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5455) ~[catalina.jar:7.0.50]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ~[catalina.jar:7.0.50]
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901) ~[catalina.jar:7.0.50]
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877) ~[catalina.jar:7.0.50]
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:634) ~[catalina.jar:7.0.50]
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1074) ~[catalina.jar:7.0.26]
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1858) ~[catalina.jar:7.0.26]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) ~[na:1.7.0_25]
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) ~[na:1.7.0_25]
        at java.util.concurrent.FutureTask.run(FutureTask.java:166) ~[na:1.7.0_25]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) ~[na:1.7.0_25]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) ~[na:1.7.0_25]
        at java.lang.Thread.run(Thread.java:724) ~[na:1.7.0_25]
通过以下方式定义一个调度程序:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">

    <!-- Enables annotation-driven task scheduling; detects @Scheduled- and 
        @Async-annotated process methods to be invoked via proxy -->
    <task:annotation-driven mode="aspectj" />
    <task:scheduler id="commonScheduler" pool-size="5" />

</beans>

另一个调度程序在中定义(为了清楚起见,删除了其他bean):


在运行时使用(为了清晰起见,删除了其他上下文)组装上下文:



为什么Spring4有这个限制?一个人应该如何应对呢?

是的,这肯定是行为上的改变。现在,每个上下文的调度程序限制为2个。我在Spring4的新WebSocket消息代理中遇到了这个问题,因为它为简单的STOMP代理和SockJS适配器分配了两个调度器。当我添加我自己的时,它与你收到的信息完全相同。我发现我不得不通过错误而不是文档来找出这个限制,这让我很恼火。Spring4文档中似乎没有描述这个问题

解决方案是创建自己的
SchedulingConfigurer
,它管理自己的
TaskScheduler
。我怀疑原因是,只有一个
TaskScheduler
实现需要添加,以便将它们彼此隔离。我是这样做的:

@Configuration
@EnableScheduling
public class MySchedulingConfigurer implements SchedulingConfigurer
{
   @Bean
   public TimedThingy timedThingy()
   {
      return new TimedThingy();
   }

  @Bean()
  public ThreadPoolTaskScheduler taskScheduler() {
     return new ThreadPoolTaskScheduler();
  }

  @Override
  public void configureTasks(ScheduledTaskRegistrar taskRegistrar)
  {
      taskRegistrar.setTaskScheduler(taskScheduler());
      taskRegistrar.addFixedRateTask(new Runnable()
      {
         public void run()
         {
            timedThingy().sendIt();
         }
      }, 1000);
  }
}

一旦我这样做了,问题就消失了,一切都如期进行。缺点是不能使用诸如
@Scheduled
等注释。。但你确实获得了更多的控制权,事情也会顺利进行。希望这能有所帮助。

您需要明确指定与
@Scheduled
注释一起使用的计划程序。只需添加
scheduler
属性:

<task:annotation-driven scheduler="commonScheduler" mode="aspectj" />
<task:scheduler id="commonScheduler" pool-size="5" />

只需将bean添加到配置中:

 @Bean()
 public ThreadPoolTaskScheduler taskScheduler() {
    return new ThreadPoolTaskScheduler();
 }

您可以显示堆栈的其余部分和实际上下文吗?您提到的代码有一个条件调度程序。size()>=2,因此它不允许2个调度程序,它只允许一个。我可以通过重写taskScheduler(正如您所做的那样)来利用@Scheduled注释。无需在configureTasks()中添加任务。我最初对SockJS的东西也有同样的问题。
<task:annotation-driven scheduler="commonScheduler" mode="aspectj" />
<task:scheduler id="commonScheduler" pool-size="5" />
 @Bean()
 public ThreadPoolTaskScheduler taskScheduler() {
    return new ThreadPoolTaskScheduler();
 }