java 从 4.2.0.RC3 升级到 4.2.0.RELEASE 时的 Spring Async 问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31816365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Async issue when upgrading from 4.2.0.RC3 to 4.2.0.RELEASE
提问by Subham Saha
I've a web application using the spring(4.2.x) artifacts spring-webmvc, spring-messaging, spring-websocket
我有一个使用 spring(4.2.x) 工件 spring-webmvc、spring-messaging、spring-websocket 的 Web 应用程序
I've the below @Enable* annotations in my spring config java class
我的 spring 配置 java 类中有以下 @Enable* 注释
@EnableWebMvc
@EnableWebSocketMessageBroker
@EnableAsync
@EnableMBeanExport
WebSocket is used for broadcasting messages to browser clients. And there are few async methods annotated with @Async
WebSocket 用于向浏览器客户端广播消息。并且很少有用@Async 注释的异步方法
The application was working fine with spring version 4.2.0.RC3. But when I changed it to the GA release 4.2.0.RELEASE, I get the below exception on startup. If I remove @EnableAsync it works fine, but I need the async functionality.
该应用程序在 spring 版本 4.2.0.RC3 上运行良好。但是当我将其更改为 GA 版本 4.2.0.RELEASE 时,我在启动时遇到以下异常。如果我删除 @EnableAsync 它工作正常,但我需要异步功能。
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.core.task.TaskExecutor] is defined: expected single matching bean but found 4: clientOutboundChannelExecutor,messageBrokerTaskScheduler,clientInboundChannelExecutor,brokerChannelExecutor
org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:366)
org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor.setBeanFactory(AsyncAnnotationBeanPostProcessor.java:128)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1597)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1565)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:305)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201)
org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:228)
org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:682)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522)
org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:539)
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
采纳答案by Artem Bilan
One of your @Configuration
must implement AsyncConfigurer
to specify the particular TaskExecutor
for @Async
methods.
您@Configuration
必须实现之一AsyncConfigurer
以指定特定TaskExecutor
的@Async
方法。
Otherwise it is in confuse which one to choose from the applicationContext
.
否则就很迷茫选择哪一个applicationContext
。
Even if it worked with RC3
it doesn't matter that it is correct, hence the bug has been fixed for GA
.
即使它可以工作RC3
,它是否正确也没有关系,因此该错误已针对GA
.
UPDATE
更新
The source code in the AsyncAnnotationBeanPostProcessor
looks like:
中的源代码AsyncAnnotationBeanPostProcessor
如下所示:
Executor executorToUse = this.executor;
if (executorToUse == null) {
try {
// Search for TaskExecutor bean... not plain Executor since that would
// match with ScheduledExecutorService as well, which is unusable for
// our purposes here. TaskExecutor is more clearly designed for it.
executorToUse = beanFactory.getBean(TaskExecutor.class);
}
catch (NoUniqueBeanDefinitionException ex) {
try {
executorToUse = beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, TaskExecutor.class);
}
catch (NoSuchBeanDefinitionException ex2) {
throw new IllegalStateException("More than one TaskExecutor bean exists within the context, " +
"and none is named 'taskExecutor'. Mark one of them as primary or name it " +
"'taskExecutor' (possibly as an alias); or specify the AsyncConfigurer interface " +
"and implement getAsyncExecutor() accordingly.", ex);
}
}
catch (NoSuchBeanDefinitionException ex) {
logger.debug("Could not find default TaskExecutor bean", ex);
// Giving up -> falling back to default executor within the advisor...
}
}
So, I guess before in between moving from RC3 to GA you have had a taskExecutor
bean on the matter.
所以,我猜在从 RC3 迁移到 GA 之前,您taskExecutor
对这个问题有所了解。
As we see by you StackTrace there is such a bean already...
正如我们在 StackTrace 中看到的,已经有这样一个 bean 了……
回答by linuxism
Add the bean at Spring application context configuration
在 Spring 应用程序上下文配置中添加 bean
@Configuration
@EnableAsync
public class AppContext extends WebMvcConfigurationSupport {
@Bean
public Executor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
}
I suggest that you refer to linuxism.tistory.com/2076
我建议你参考linuxism.tistory.com/2076
If you declare your executors in XML, then you can create a class and name it TaskExecutor. Then when Spring tries to find the TaskExecutor bean, it will find this one.
如果您在 XML 中声明您的执行程序,那么您可以创建一个类并将其命名为 TaskExecutor。然后当 Spring 试图找到 TaskExecutor bean 时,它会找到这个。
@Component
public class TaskExecutor extends SimpleAsyncTaskExecutor {
}
回答by tnabeel
For those like myself who are still using old-fashioned XML configuration....
对于像我这样仍在使用老式 XML 配置的人......
This was working for me before Spring 4.2:
这在 Spring 4.2 之前对我有用:
<task:annotation-driven />
<task:executor id="executorA" pool-size="50" />
<task:executor id="executorB" pool-size="100" />
@Async("executorA")
public void executeA() {}
@Async("executorB")
public void executeB() {}
As pointed out by Artem, Spring 4.2 is getting confused about which pool to use for qualifier-less async methods even when you don't have such methods in your application.
正如 Artem 所指出的那样,即使您的应用程序中没有此类方法,Spring 4.2 也会对使用哪个池用于无限定符的异步方法感到困惑。
To fix it, I used this:
为了修复它,我使用了这个:
<task:annotation-driven executor="defaultExecutor"/>
<task:executor id="defaultExecutor" pool-size="1" queue-capacity="0"/>
<task:executor id="executorA" pool-size="50" />
<task:executor id="executorB" pool-size="100" />
@Async("executorA")
public void executeA() {}
@Async("executorB")
public void executeB() {}
Note that if you add qualifier-less @Async methods, then those methods will use the defaultExectuor thread-pool:
请注意,如果您添加无限定符的 @Async 方法,那么这些方法将使用 defaultExectuor 线程池:
@Async
public void myDefaultExecute() {}
And, of course, executeA() calls will use executorA thread-pool and executeB() calls will use executorB thread-pool.
当然,executeA() 调用将使用 executorA 线程池,executeB() 调用将使用 executorB 线程池。
Hope that helps.
希望有帮助。