情景:
在某些业务过程,对于一些耗时较长,用户无需等待的过程,能够使用异步方法进行处理。使用spring @Async能够实现异步方法java
实现:spring
1.在spring配置文件中加入异步支持express
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd"> <context:annotation-config /> <!--扫描注解 --> <context:component-scan base-package="com.xx.yy.*" /> <!-- 支持异步方法执行 --> <task:annotation-driven /> </beans>
2.写异步方法spring-mvc
@Component public class AsyncTaskTest { @Async public static void doSomething()throws Exception{ Thread.sleep(10000); System.out.println("begin doSomthing...."); Thread.sleep(10000); System.out.println("end doSomthing...."); } }
3.调用异步方法mvc
@Controller public class DebugController { @Autowired AsyncTaskTest asyncTask; @RequestMapping("/main") public String asynTest() { try { System.out.println("我开始执行了!"); asyncTask.doSomething(); System.out.println("我执行结束了!"); } catch (Exception e) { e.printStackTrace(); } return "main"; } }
4.常见问题app
作了一、二、3程序不必定能正确执行异步方法。由于异步方法有可能由于某些问题而失效。常见的异步失效缘由有:
一、异步方法和调用类不要在同一个类中
二、注解扫描时,要注意过滤,避免重复实例化,由于存在覆盖问题,@Async就失效了异步
问题2举例,若是除了applicationContext.xml 中配置了包扫描外,还在dispatcher-Servlet.xml中还配置了包扫描。则会出现异步失效问题。async
<context:component-scan base-package="com.xx.yy.*" />
解决方案:
1.在dispatcher-Servlet.xml 中指定扫描某个包spa
<context:component-scan base-package="com.xx.yy.controller" > </context:component-scan>
只有@Async异步方法再也不该包下才能避免被重复扫描。code
2.指定扫描包下的某个标签
<context:component-scan base-package="com.xx.yy.*" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
实际上<context:component-scan> 有个属性use-default-filters它的默认值为true,会扫描指定包下的所有的标有@Component的类,并注册成bean.也就是@Component的子注解@Service,@Reposity等。因此若是仅仅是在配置文件中这么写:
<context:component-scan base-package="com.xx.yy.*" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
Use-default-filter此时为true那么会对base-package包或者子包下的全部的进行Java类进行扫描,并把@Component的类的java类注册成bean,因此仍是不能避免异步方法所在类被重复扫描。
若是须要指定一些包扫描,一些包不扫描,则须要修改Use-dafault-filter的默认值。
Use-dafault-filters=”false”的状况下:<context:exclude-filter>指定的不扫描,<context:include-filter>指定的扫描。
<context:component-scan base-package="com.xx.yy.*" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
-----end-----