Spring @Async不工作

@Service -annotated类中的@Async方法不是asynchronous调用 – 它阻塞了线程。

我在我的configuration文件中有<task: annotation-driven /> ,并且对该方法的调用来自于类之外,所以代理应该被击中。 当我遍历代码时,代理确实被击中了,但是它似乎并没有到任何与任务执行器中运行相关的类中。

我已经在AsyncExecutionInterceptor放置了断点,并且它们永远不会被击中。 我已经debugging到AsyncAnnotationBeanPostProcessor并可以看到得到应用的build议。

这个服务被定义为一个接口(在@Async方法中注释的方法是很好的方法),实现的方法注解@Async 。 两者都没有标记@Transactional

任何想法可能出了什么问题?

– = UPDATE = –

奇怪的是,它只在我的app-servlet.xml文件中有我的task XML元素,而不是在我的app-services.xml文件中,以及如果我从那里做服务的组件扫描。 通常我只有一个XML文件,其中只有控制器(并相应地限制组件扫描),另一个XML文件包含服务(同样,组件扫描受限制,使得它不会重新扫描其他加载的控制器文件)。

APP-servlet.xml中

 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:webflow="http://www.springframework.org/schema/webflow-config" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd" > <task:annotation-driven executor="executor" /> <task:executor id="executor" pool-size="7"/> <!-- Enable controller annotations --> <context:component-scan base-package="com.package.store"> <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> --> </context:component-scan> <tx:annotation-driven/> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <mvc:annotation-driven conversion-service="conversionService" /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> 

app-services.xml (在这里指定时不起作用)

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <!-- Set up Spring to scan through various packages to find annotated classes --> <context:component-scan base-package="com.package.store"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <task:annotation-driven executor="han" /> <task:executor id="han" pool-size="6"/> ... 

我是否在configuration中缺less显而易见的东西,或者configuration元素之间是否存在一些微妙的相互作用?

在Ryan Stewart的这个出色的答案的帮助下,我弄清楚了这一点(至less对于我的具体问题)。

简而言之, ContextLoaderListener (通常来自applicationContext.xml)加载的上下文是DispatcherServlet (通常来自*-servlet.xml )加载的上下文的父代。 如果在上下文中声明/组件扫描了@Async方法,则子上下文( DispatcherServlet )中的版本将覆盖父上下文( ContextLoaderListener )中的版本。 我通过从*-servlet.xml中的组件扫描中排除该组件来validation这一点 – 现在按预期工作。

对我来说,解决scheme是在我的@Configuration注释类中添加@EnableAsync

 @Configuration @ComponentScan("bla.package") @EnableAsync public class BlaConfiguration { } 

现在,包含bla.package包含@Async注释方法的类可以真正使它们asynchronous调用。

  1. 尝试向所有支持此属性的<*:annotation-driven/>元素添加proxy-target-class="true"
  2. 检查用@Async注释的方法@Async是公共的。

JiříVypědřík的答案解决了我的问题。 特别,

  1. 检查用@Async注释的方法是否是公共的。

另一个有用的信息来自Spring教程https://spring.io/guides/gs/async-method/

创buildFacebookLookupService类的本地实例不允许findPage方法asynchronous运行。 它必须在@Configuration类中创build,或者由@ComponentScan拾取。

这意味着如果你有一个静态方法Foo.bar(),以这种方式调用它将不会在asynchronous中执行,即使它是用@Async注释的。 你必须使用@Component注释Foo,并在调用类中获取Foo的@Autowired实例。

也就是说,如果在Foo类中有一个带注释的方法栏:

 @Component class Foo { @Async public static void bar(){ /* ... */ } @Async public void bar2(){ /* ... */ } } 

在你的调用者类中:

 class Test { @Autowired Foo foo; public test(){ Foo.bar(); // Not async foo.bar(); // Not async foo.bar2(); // Async } } 

编辑:似乎静态调用它也不会在asynchronous中执行它。

希望这可以帮助。

首先让你的.xmlconfiguration如下所示:

 <task:scheduler id="myScheduler" pool-size="10" /> <task:executor id="myExecutor" pool-size="10" /> <task:annotation-driven executor="myExecutor" scheduler="myScheduler" proxy-target-class="true" /> 

(是,调度程序计数和执行程序线程池大小是可configuration的)

或者只是使用默认值:

 <!-- enable task annotation to support @Async, @Scheduled, ... --> <task:annotation-driven /> 

其次确保@Async方法是公共的。

我意识到下面的教程asynchronous方法教程代码 ,我的问题来源是:带有注释的@Async方法的bean没有创build包装在代理中。 我开始挖掘,并意识到有一个消息说

Bean'NameOfTheBean'没有资格被所有BeanPostProcessors处理(例如:不适合自动代理)

你可以在这里看到有关这个问题的回应,其基本上每个Bean都需要BeanPostProcessors,所以在这里注入的每个bean及其依赖将被其他BeanPostProcessors排除在后面,因为它破坏了bean的生命周期。 因此,请确定是哪个BeanPostProcessor导致了这个问题,并且不使用或者在其中创buildbean。

在我的情况下,我有这种configuration

 @EnableWs @Configuration public class WebServiceConfig extends WsConfigurerAdapter { @Autowired private Wss4jSecurityInterceptor securityInterceptor; @Autowired private DefaultPayloadLoggingInterceptor payloadLoggingInterceptor; @Override public void addInterceptors(List<EndpointInterceptor> interceptors) { interceptors.add(securityInterceptor); interceptors.add(payloadLoggingInterceptor); } } 

WsConfigurerAdapter实际上是一个BeanPostProcessor ,你意识到这一点,因为总是有一个模式: @Configuration扩展了类并覆盖了一些函数来安装或调整一些非function特性(比如Web服务或安全性)所涉及的bean。

在上面的例子中,你必须重写addInterceptors并添加拦截器bean,所以如果你在DefaultPayloadLoggingInterceptor里面使用@Async这样的注解, @Async不能工作。 解决办法是什么? 搭乘WsConfigurerAdapter开始。 挖了一点后,我意识到一个名为PayloadRootAnnotationMethodEndpointMapping的类在最后是所有有效的拦截器,所以我做了手动insted重写一个函数。

 @EnableWs @Configuration public class WebServiceConfig { @Autowired private Wss4jSecurityInterceptor securityInterceptor; @Autowired private DefaultPayloadLoggingInterceptor payloadLoggingInterceptor; @Autowired public void setupInterceptors(PayloadRootAnnotationMethodEndpointMapping endpointMapping) { EndpointInterceptor[] interceptors = { securityInterceptor, payloadLoggingInterceptor }; endpointMapping.setInterceptors(interceptors); } } 

所以这将在所有BeanPostProcessor完成其工作后运行。 当该方结束并安装拦截器bean时, setupInterceptors函数将运行。 这个用例可能被外推到像Security这样的情况。

结论:

  • 如果你正在使用从某些自动运行某些给定函数的类中扩展的@Configuration,并且你重写了它们,那么你可能在BeanPostProcessor内部,所以不要在那里注入bean并尝试使用AOP行为,因为它不会工作,看到Spring用控制台中的前面提到的消息告诉你。 在这些情况下,不要使用bean,而是使用new子句。
  • 如果你需要使用bean digg关于哪个类是最后要设置的bean,那么@Autowired并添加这些bean,就像我以前一样。

我希望这可以为你节省一些时间。

@Async不能与生命周期callback(如@PostConstruct)结合使用。 为了asynchronous地初始化Spring bean,你现在必须使用一个单独的初始化Spring bean,然后在目标上调用@Async注释的方法。

 public class SampleBeanImpl implements SampleBean { @Async void doSomething() { … } } public class SampleBeanInititalizer { private final SampleBean bean; public SampleBeanInitializer(SampleBean bean) { this.bean = bean; } @PostConstruct public void initialize() { bean.doSomething(); } } 

资源

为asynchronousbean编写一个独立的Springconfiguration。
例如:

 @Configuration @ComponentScan(basePackages="xxxxxxxxxxxxxxxxxxxxx") @EnableAsync public class AsyncConfig { /** * used by asynchronous event listener. * @return */ @Bean(name = "asynchronousListenerExecutor") public Executor createAsynchronousListenerExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(100); executor.initialize(); return executor; } } 

我解决了这个问题。