2015-08-04 37 views
17

Mam aplikacji internetowych za pomocą sprężyny (4.2.x) artefakty wiosna-webmvc, wiosna-wiadomości, wiosna-websocketWiosna asynchroniczny problem podczas aktualizacji 4.2.0.RC3 do 4.2.0.RELEASE

mam poniżej @ Włącz * adnotacje w moim wiosna config klasy java

@EnableWebMvc 
@EnableWebSocketMessageBroker 
@EnableAsync 
@EnableMBeanExport 

websocket służy do nadawania komunikatów do klientów przeglądarek. A jest kilka metod asynchronicznych opatrzonych adnotacją @Aynchrony

Aplikacja działała poprawnie z wersją wiosną 4.2.0.RC3. Ale kiedy zmieniłem go na GA release 4.2.0.RELEASE, otrzymuję poniższy wyjątek przy starcie. Jeśli usuniemy @EnableAsync, działa dobrze, ale potrzebuję funkcji asynchronicznej.

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) 

Odpowiedz

8

jeden z twoich @Configuration musi wdrożyć AsyncConfigurer określić szczególne TaskExecutor dla @Async metod.

W przeciwnym razie nie ma pewności, który wybrać spośród applicationContext.

Nawet jeśli zadziałało z RC3, nie ma znaczenia, że ​​jest poprawny, dlatego błąd został naprawiony dla GA.

UPDATE

Kod źródłowy w AsyncAnnotationBeanPostProcessor wygląda następująco:

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

Tak, myślę, że zanim w między ruchu z RC3 do GA miałeś taskExecutor fasolkę w tej sprawie.

Jak widzimy przez Państwo StackTrace istnieje już taka fasola ...

+2

Który z nich był domyślny w RC3 i jaka jest między nimi różnica? – EpicPandaForce

+0

@Artem Nie ma wzmianki o określeniu konkretnego 'TaskExecutor' dla metod' @ Async' w Dokumentacji referencyjnej. Myślę, że wiosna powinna zapewnić domyślne 'TaskExecutor' jeśli żadna nie jest określona. –

+0

Zobacz 'UPDATE' w mojej odpowiedzi. –

15

Dodaj Bean w konfiguracji kontekstowego aplikacji Wiosna

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

I sugerują, że odnoszą się do linuxism.tistory.com/2076

If Deklarujesz swoje executory w XML, możesz stworzyć klasę i nazwać ją TaskExecutor. Wtedy, gdy Spring spróbuje znaleźć fasolę TaskExecutor, znajdzie ją.

@Component 
public class TaskExecutor extends SimpleAsyncTaskExecutor { 
} 
1

Dla tych, jak ja, którzy nadal korzystają konfigurację staromodny XML ....

To działa na mnie przed wiosną 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() {} 

Jak zauważył Artem, Wiosna 4.2 zaczyna się mylić co do tego, której puli użyć do stosowania metod asynchronicznych bez kwalifikacji, nawet jeśli nie masz takich metod w swojej aplikacji.

Aby go naprawić, kiedyś tak:

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

Zauważ, że jeśli dodać metody kwalifikatora mniej @Async, następnie te metody użyje defaultExectuor nitki basenu:

@Async 
public void myDefaultExecute() {} 

I , oczywiście, wywołania executeA() będą używały executorA puli wątków, a executeB() będą używać executorB-puli wątków.

Nadzieję, że pomaga.