情景:
在某些業務過程,對於一些耗時較長,用戶無需等待的過程,能夠使用異步方法進行處理。使用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-----