Spring(4.2.x)アーティファクトspring-webmvc、spring-messaging、spring-websocketを使用するWebアプリケーションがあります
Spring config Javaクラスに以下の@ Enable *アノテーションがあります
@EnableWebMvc
@EnableWebSocketMessageBroker
@EnableAsync
@EnableMBeanExport
WebSocketは、ブラウザクライアントにメッセージをブロードキャストするために使用されます。そして、@ Asyncで注釈されたいくつかの非同期メソッドがあります
アプリケーションは、Springバージョン4.2.0.RC3で正常に動作していました。しかし、GA release 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$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)
@Configuration
メソッドに特定のAsyncConfigurer
を指定するには、@Async
の1つがTaskExecutor
を実装する必要があります。
そうしないと、applicationContext
からどちらを選択するかが混乱します。
RC3
で機能したとしても、それが正しいかどうかは問題ではないため、GA
のバグが修正されました。
[〜#〜]更新[〜#〜]
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...
}
}
そのため、以前はRC3からGAへの移行の合間に、問題についてtaskExecutor
Beanを使用していたと思います。
StackTraceで確認したように、すでにそのようなBeanがあります...
Springアプリケーションコンテキスト構成でBeanを追加する
@Configuration
@EnableAsync
public class AppContext extends WebMvcConfigurationSupport {
@Bean
public Executor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
}
linuxism.tistory.com/2076 を参照することをお勧めします
ExecutorをXMLで宣言する場合は、クラスを作成してTaskExecutorという名前を付けることができます。次に、SpringがTaskExecutor Beanを見つけようとすると、これが見つかります。
@Component
public class TaskExecutor extends SimpleAsyncTaskExecutor {
}
昔ながらのXML構成をまだ使用している私のような人のために...
これは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() {}
Artemが指摘したように、Spring 4.2は、アプリケーションにそのようなメソッドがない場合でも、修飾子なしの非同期メソッドに使用するプールについて混乱しています。
それを修正するために、私はこれを使用しました:
<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() {}
修飾子のない@Asyncメソッドを追加すると、それらのメソッドはdefaultExectuorスレッドプールを使用することに注意してください。
@Async
public void myDefaultExecute() {}
そしてもちろん、executeA()呼び出しはexecutorAスレッドプールを使用し、executeB()呼び出しはexecutorBスレッドプールを使用します。
お役に立てば幸いです。