java - mvc - Problema de Spring Async al actualizar de 4.2.0.RC3 a 4.2.0.RELEASE
spring mvc wikipedia (3)
Agregar el bean en la configuración de contexto de la aplicación Spring.
@Configuration
@EnableAsync
public class AppContext extends WebMvcConfigurationSupport {
@Bean
public Executor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
}
Le sugiero que se refiera a linuxism.tistory.com/2076
Si declara sus ejecutores en XML, puede crear una clase y denominarlo TaskExecutor. Luego, cuando Spring trate de encontrar el bean TaskExecutor, encontrará este.
@Component
public class TaskExecutor extends SimpleAsyncTaskExecutor {
}
Tengo una aplicación web que utiliza los artefactos spring (4.2.x) spring-webmvc, spring-messaging, spring-websocket
Tengo las siguientes anotaciones @ Enable * en mi clase java spring config
@EnableWebMvc
@EnableWebSocketMessageBroker
@EnableAsync
@EnableMBeanExport
WebSocket se utiliza para transmitir mensajes a los clientes del navegador. Y hay pocos métodos asíncronos anotados con @Async
La aplicación funcionaba bien con la versión de primavera 4.2.0.RC3. Pero cuando lo cambié a la versión 4.2.0.RELEASE de GA, obtengo la siguiente excepción al inicio. Si elimino @EnableAsync, funciona bien, pero necesito la funcionalidad asíncrona.
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$1.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)
Para aquellos que, como yo, que todavía están usando la configuración XML pasada de moda ...
Esto estaba funcionando para mí antes de la primavera 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() {}
Como señala Artem, Spring 4.2 se está confundiendo acerca de qué grupo usar para los métodos asíncronos sin calificador, incluso cuando no tiene dichos métodos en su aplicación.
Para arreglarlo, utilicé esto:
<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() {}
Tenga en cuenta que si agrega métodos @Async sin calificador, esos métodos utilizarán el grupo de subprocesos defaultExectuor:
@Async
public void myDefaultExecute() {}
Y, por supuesto, las llamadas executeA () utilizarán un grupo de subprocesos executorA y las llamadas executeB () utilizarán un grupo de subprocesos executorB.
Espero que ayude.
Uno de sus @Configuration
debe implementar AsyncConfigurer
para especificar el TaskExecutor
particular para los métodos de @Async
.
De lo contrario, se confunde cuál elegir en el contexto de applicationContext
.
Incluso si funcionó con RC3
, no importa que sea correcto, por lo tanto, el error se ha corregido para GA
.
ACTUALIZAR
El código fuente en el AsyncAnnotationBeanPostProcessor
ve así:
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...
}
}
Entonces, supongo que antes de pasar de RC3 a GA ha tenido un bean taskExecutor
al respecto.
Como vemos por StackTrace, ya existe un bean ...