Spring Async issue when upgrading from 4.2.0.RC3 to 4.2.0.RELEASE

折月煮酒 提交于 2019-11-30 03:23:15

One of your @Configuration must implement AsyncConfigurer to specify the particular TaskExecutor for @Async methods.

Otherwise it is in confuse which one to choose from the applicationContext.

Even if it worked with RC3 it doesn't matter that it is correct, hence the bug has been fixed for GA.

UPDATE

The source code in the AsyncAnnotationBeanPostProcessor looks like:

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.

As we see by you StackTrace there is such a bean already...

linuxism

Add the bean at Spring application context configuration

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

I suggest that you refer to 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.

@Component
public class TaskExecutor extends SimpleAsyncTaskExecutor {
}

For those like myself who are still using old-fashioned XML configuration....

This was working for me before 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.

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

And, of course, executeA() calls will use executorA thread-pool and executeB() calls will use executorB thread-pool.

Hope that helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!