2015-08-04 13 views
17

Ho un'applicazione web utilizzando la molla (4.2.x) artefatti primavera-webmvc, primavera-messaging, la primavera-websocketnumero della primavera Async durante l'aggiornamento da 4.2.0.RC3 a 4.2.0.RELEASE

ho il seguito @ Attiva annotazioni * nel mio config primavera classe Java

@EnableWebMvc 
@EnableWebSocketMessageBroker 
@EnableAsync 
@EnableMBeanExport 

WebSocket è usato per trasmettere messaggi ai client browser. E ci sono alcuni metodi asincroni annotati con @Async

L'applicazione stava funzionando bene con la versione di primavera 4.2.0.RC3. Ma quando ho cambiato il GA 4.2.0.RELEASE, ottengo l'eccezione di seguito all'avvio. Se rimuovo @EnableAsync, funziona bene, ma ho bisogno della funzionalità asincrona.

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) 

risposta

8

Uno dei vostri @Configuration devono attuare AsyncConfigurer per specificare il particolare TaskExecutor per @Async metodi.

Altrimenti è confuso quale scegliere tra applicationContext.

Anche se ha funzionato con RC3 non importa che sia corretto, quindi il bug è stato risolto per GA.

UPDATE

Il codice sorgente nel AsyncAnnotationBeanPostProcessor assomiglia:

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... 
    } 
} 

Quindi, credo che prima di tra passando da RC3 a GA avete avuto una taskExecutor fagiolo in materia.

Come si vede da voi StackTrace v'è una tale fagioli già ...

+2

Quale era l'impostazione predefinita in RC3 e qual è la differenza tra loro? – EpicPandaForce

+0

@Artem Non viene menzionato alcun specifico 'TaskExecutor' per i metodi' @ Async' nella Documentazione di riferimento. Penso che la primavera dovrebbe fornire un 'TaskExecutor' predefinito se non ne viene specificato nessuno. –

+0

Vedere un 'UPDATE' nella mia risposta. –

15

Aggiungere il fagiolo alla configurazione di contesto di applicazione Primavera

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

vi suggerisco di fare riferimento al linuxism.tistory.com/2076

Se dichiari i tuoi esecutori in XML, quindi puoi creare una classe e nominarla TaskExecutor. Quindi, quando Spring tenta di trovare il bean TaskExecutor, troverà questo.

@Component 
public class TaskExecutor extends SimpleAsyncTaskExecutor { 
} 
1

Per quelli come me che stanno ancora utilizzando la configurazione vecchio stile XML ....

Questo stava lavorando per me prima di 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() {} 

Come sottolineato da Artem, Spring 4.2 si sta confondendo su quale pool utilizzare per i metodi asincroni senza qualificatore anche quando non si dispone di tali metodi nella propria applicazione.

Per risolvere il problema, ho usato questo:

<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() {} 

Si noti che se si aggiungono i metodi di qualificazione-less @Async, poi quei metodi utilizzeranno il defaultExectuor filo-piscina:

@Async 
public void myDefaultExecute() {} 

E , ovviamente, le chiamate executeA() useranno il pool di thread executorA e le chiamate executeB() useranno il pool di thread executorB.

Spero che questo aiuti.

Problemi correlati