Spring中@Async註解實現「方法」的異步調用

1、簡介
在Java應用中,絕大多數狀況下都是經過同步的方式來實現交互處理的;可是在處理與第三方系統交互的時候,容易形成響應遲緩的狀況數據庫

2、解決辦法
辦法一:採用多線程實現異步操做多線程

新建一個線程類:app

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("。。。。。異步方法調用了。。。。。");
    }
}

在須要異步操做的地方,開啓異步線程:異步

@RequestMapping("/index")
public String loginpage() {
    //開啓異步操做
   Thread thread1=new Thread(new MyThread());
   thread1.start();
    return "login";
}

方法二:@Async註解
在Spring中,基於@Async標註的方法,稱之爲異步方法;這些方法將在執行的時候,將會在獨立的線程中被執行,調用者無需等待它的完成,便可繼續其餘的操做。
(1)基於Java配置的啓用方式:
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... } 
async

(2)基於XML配置文件的啓用方式
//加載bean
<bean id="asyncTest" class="com.utils.AsyncTest" lazy-init="false"/>
<task:executor id="myexecutor"pool-size="5"/> 
<task:annotation-driven executor="myexecutor"/>
ide

3、實際使用
(1)新建一個異步操做類測試

@Component
public class AsyncTest {
    @Async("myexecutor")
    public void sayHello(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello...hello");
    }
}

(2)在須要異步的地方,使用上述方法:spa

@Autowired
private AsyncTest asyncTest;
@RequestMapping("/index")
public String loginpage() {
    System.out.println("開始調用 asyncTest.sayHello()");
    asyncTest.sayHello();
    System.out.println("結束調用 asyncTest.sayHello()");
    return "login";
}


上述方法返回值是void的演示,還有存在返回值的異步操做;線程

改寫sayHello()方法

@Async("myexecutor")
public Future<String> sayHello(){
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("hello...hello");
    return new AsyncResult<String>("這是sayHello()返回值");
}

 

打印sayHello()返回值

@RequestMapping("/index")
public String loginpage() throws ExecutionException, InterruptedException {
    System.out.println("開始調用 asyncTest.sayHello()");
    Future<String> results=asyncTest.sayHello();
    System.out.println("結束調用 asyncTest.sayHello()");
    while(true) { //這裏使用了循環判斷,等待獲取結果信息
            if (results.isDone()) { //判斷是否執行完畢
                System.out.println("Result from asynchronous process - " + results.get());
                break;
            }
        }
    return "login";
}


獲取異步方法的結果信息,是經過不停的檢查Future的狀態來獲取當前的異步方法是否執行完畢來實現的
經實際測試發現,若是打印異步操做返回值,則是等待異步操做執行結束後才能得到返回值,如此一來整個流程下來花費時間和同步方法同樣。code


4、@Async調用中的事務處理機制
在@Async標註的方法,同時也適用了@Transactional進行了標註;在其調用數據庫操做之時,將沒法產生事務管理的控制,緣由就在於其是基於異步處理的操做。那該如何給這些操做添加事務管理呢?能夠將須要事務管理操做的方法放置到異步方法內部,在內部被調用的方法上添加@Transactional.
例如:

 方法A,使用了@Async/@Transactional來標註,可是沒法產生事務控制的目的。 方法B,使用了@Async來標註,  B中調用了C、D,C/D分別使用@Transactional作了標註,則可實現事務控制的目的。

相關文章
相關標籤/搜索