在沒有使用spring boot之前,我們的做法是在配置文件中定義一個(gè)任務(wù)池,然后將@Async注解的任務(wù)丟到任務(wù)池中去執(zhí)行,那么在spring boot中,怎么來實(shí)現(xiàn)異步任務(wù)的調(diào)用了,方法更簡(jiǎn)單。
我們還是結(jié)合前面
spring boot整合JMS(ActiveMQ實(shí)現(xiàn))
這篇博客里面的代碼來實(shí)現(xiàn)。
一、功能說明
消費(fèi)者在監(jiān)聽到隊(duì)列里面的消息時(shí),將接收消息的任務(wù)作為異步任務(wù)處理。
二、代碼修改
消費(fèi)者1:
1
2
3
4
5
6
7
8
9
10
11
12
|
package com.chhliu.springboot.jms; import org.springframework.jms.annotation.JmsListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component public class Consumer { @JmsListener (destination = "mytest.queue" ) @Async //該方法會(huì)異步執(zhí)行,也就是說主線程會(huì)直接跳過該方法,而是使用線程池中的線程來執(zhí)行該方法 public void receiveQueue(String text) { System.out.println(Thread.currentThread().getName()+ ":Consumer收到的報(bào)文為:" +text); } } |
消費(fèi)者2:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.chhliu.springboot.jms; import org.springframework.jms.annotation.JmsListener; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Component; @Component public class Consumer2 { @JmsListener (destination = "mytest.queue" ) @SendTo ( "out.queue" ) public String receiveQueue(String text) { System.out.println(Thread.currentThread().getName()+ ":Consumer2收到的報(bào)文為:" +text); return "return message" +text; } } |
在測(cè)試類上添加如下注解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.chhliu.springboot.jms; import javax.jms.Destination; import org.apache.activemq.command.ActiveMQQueue; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.test.context.junit4.SpringRunner; @RunWith (SpringRunner. class ) @SpringBootTest @EnableAsync // 開啟異步任務(wù)支持 public class SpringbootJmsApplicationTests { @Autowired private Producer producer; @Test public void contextLoads() throws InterruptedException { Destination destination = new ActiveMQQueue( "mytest.queue" ); for ( int i= 0 ; i< 100 ; i++){ producer.sendMessage(destination, "myname is chhliu!!!" ); } } } |
三、測(cè)試結(jié)果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! 從out.queue隊(duì)列收到的回復(fù)報(bào)文為: return messagemyname is chhliu!!! SimpleAsyncTaskExecutor- 45 :Consumer收到的報(bào)文為:myname is chhliu!!! DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! 從out.queue隊(duì)列收到的回復(fù)報(bào)文為: return messagemyname is chhliu!!! SimpleAsyncTaskExecutor- 46 :Consumer收到的報(bào)文為:myname is chhliu!!! DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! 從out.queue隊(duì)列收到的回復(fù)報(bào)文為: return messagemyname is chhliu!!! SimpleAsyncTaskExecutor- 47 :Consumer收到的報(bào)文為:myname is chhliu!!! DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! 從out.queue隊(duì)列收到的回復(fù)報(bào)文為: return messagemyname is chhliu!!! SimpleAsyncTaskExecutor- 48 :Consumer收到的報(bào)文為:myname is chhliu!!! DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! 從out.queue隊(duì)列收到的回復(fù)報(bào)文為: return messagemyname is chhliu!!! SimpleAsyncTaskExecutor- 49 :Consumer收到的報(bào)文為:myname is chhliu!!! DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! 從out.queue隊(duì)列收到的回復(fù)報(bào)文為: return messagemyname is chhliu!!! SimpleAsyncTaskExecutor- 50 :Consumer收到的報(bào)文為:myname is chhliu!!! DefaultMessageListenerContainer- 1 :Consumer2收到的報(bào)文為:myname is chhliu!!! |
從上面的測(cè)試結(jié)果可以看出,由于消費(fèi)者2沒有使用異步任務(wù)方式,所以消費(fèi)者2消費(fèi)消息都是由固定的線程DefaultMessageListenerContainer-1這個(gè)線程來處理的,而消費(fèi)者1由于使用了異步任務(wù)的方式,每次處理接收到的消息都是由不同的線程來處理的,當(dāng)接收到消息時(shí),直接將任務(wù)丟到任務(wù)池中去處理,而主線程則繼續(xù)跑,從測(cè)試結(jié)果中還可以推斷出,spring boot默認(rèn)使用了newCachedThreadPool線程池來實(shí)現(xiàn)。
關(guān)于線程池的具體用法,請(qǐng)參考我的另一篇博文:http://www.zmynmublwnt.cn/article/153012.html
四、異步任務(wù)有返回
在實(shí)際的開發(fā)中,我們會(huì)經(jīng)常遇到異步任務(wù)有返回的情況,那么在spring boot中,怎么來實(shí)現(xiàn)了?
下面以異步發(fā)郵件為例,來進(jìn)行說明,示例代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Async ( "taskExecutePool" ) // 異步任務(wù)會(huì)提交到taskExecutePool任務(wù)池中執(zhí)行 public Future<Response> doSendEmail(MailInfo mailInfo) { // 異步任務(wù)返回,使用Future<Response>來異步返回 log.info(Thread.currentThread().getName()+ "調(diào)用了doSendEmail異步方法!" ); SendMailSession session = null ; Response res = new Response(); boolean isOK = sendEmail(mailInfo); // 具體發(fā)郵件的方法 if (isOK){ res.setSuccess( true ); } else { res.setSuccess( false ); } return new AsyncResult<Response>(res); |
返回之后怎么使用?示例代碼如下:
1
2
|
Future<Response> result = taskJob.doSendEmail(mailInfo); res = result.get( 6 , TimeUnit.SECONDS); |
這樣就可以獲取到異步任務(wù)的返回了!
總結(jié)
以上所述是小編給大家介紹的spring boot異步(Async)任務(wù)調(diào)度實(shí)現(xiàn)方法,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)服務(wù)器之家網(wǎng)站的支持!
原文鏈接:http://blog.csdn.net/liuchuanhong1/article/details/54605697