spring @Async處理異步任務以及常見「異步失效」問題

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

相關文章
相關標籤/搜索