廢話前言:java
首先說一下我爲何使用事件,好比如今建立一個訂單可是我建立成功後要給客戶發送一條短信和一個郵件提醒,自己沒建立訂單一系列操做就須要不少時間可是我還要去發送短信和郵件,期間還要調用其它服務來實現耗時比較長達不到客戶的滿意度,因此使用的方式能夠說一下:spring
1:activeMQ(異步)app
2:使用spring事件監聽(同步+異步)異步
下面咱們只說第二種方式async
/**
* 自定義管理事件
*/
public class MessageEvent extends ApplicationEvent {
/**
* 在自定義事件的構造方法中除了第一個source參數,其餘參數均可以去自定義
* 能夠根據項目實際狀況進行監聽傳參
*/
private final String message;//事件交互信息
private final String JNDI;//過濾指定監聽
private final String desc;//描述可傳特殊參數不知足時擴展改爲MAP/Object目前沒遇到太特殊的
/*
* 保存JNDI的信息
* 用來過濾具體執行的監聽方法
*/
public MessageEvent(Object source,String message,String desc) {
super(source);
this.message = message;
this.JNDI = (String) source;
this.desc = desc;
}
public String getJNDI() {
return JNDI;
}
public String getMessage() {
return message;
}
public String getDesc() {
return desc;
}
第二:定義一個監聽ide
/**
* 測試用自定義監聽器,監聽事件爲MyEvent
*/
@Component
public class MyLisenter implements ApplicationListener<MyEvent> {
/**
* 對監聽到的事件進行處理
* @param myEvent
*/
@Override
public void onApplicationEvent(MyEvent myEvent) {
/*
這裏不作處理,只對消息進行透傳打印,實際狀況,
能夠根據項目進行邏輯進行處理
*/
myEvent.printMsg(myEvent.getMsg());
System.out.println("監聽到。。。");
}
}
第三:如今自定義事件和監聽器都好了,咱們就來看看第一個問題,監聽器如何部署到ApplicationContext,有四種方式能夠實現,咱們一個一個看:函數
2.監聽器部署到ApplicationContext,實際上就是將將監聽器交給Spring 容器管理,因此最簡單的方法只需在自定義的PrintListener上加上@Component註解就好了把上圖//事件配置監聽注掉就好了這個註解就能夠實現。源碼分析
4.使用@EventListener註解,先看代碼,創建一個普通的java類並交給spring容器,其中一個處理event的方法,加上該註解,刪掉配置文件中的配置。測試
咱們注意到ApplicationContext的事件發佈能力是繼承自ApplicationEventPublisher,而且ApplicationContextAware中有這樣一段註釋:優化
測試代碼:
(異步方式,可指定監聽事件)
第一步:在啓動類添加註解@EnableAsync,自定義線程池類
建立一個配置類ExecutorConfig,用來定義如何建立一個ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync這兩個註解,表示這是個配置類,而且是線程池的配置類
以下所示:
/**
* 鏈接池配置
*/
@Configuration
@EnableAsync
public class TaskExecutePool {
private static final Logger log = LoggerFactory.getLogger(TaskExecutePool.class);
@Bean("myTaskAsyncPool")
public Executor myTaskAsyncPool() {
log.info("start TaskExecutePool myTaskAsyncPool");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心線程數
executor.setCorePoolSize(10);
//配置核心線程數
executor.setMaxPoolSize(20);
//配置隊列容量
executor.setQueueCapacity(1000);
//設置線程活躍時間
executor.setKeepAliveSeconds(60);
//設置線程名
executor.setThreadNamePrefix("myTaskAsyn-");
//設置拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
注意,上面的方法名稱爲asyncServiceExecutor,
@Async("asyncServiceExecutor"):即配置線程池的方法名,此處若是不寫自定義線程池的方法名,會使用默認的線程池
第二步:自定義事件發佈類
/**
* 自定義管理事件
*/
public class MessageEvent extends ApplicationEvent {
/**
* 在自定義事件的構造方法中除了第一個source參數,其餘參數均可以去自定義
* 能夠根據項目實際狀況進行監聽傳參
*/
private final String message;//事件交互信息
private final String JNDI;//過濾指定監聽
private final String desc;//描述可傳特殊參數不知足時擴展改爲MAP/Object目前沒遇到太特殊的
/*
* 保存JNDI的信息
* 用來過濾具體執行的監聽方法
*/
public MessageEvent(Object source,String message,String desc) {
super(source);
this.message = message;
this.JNDI = (String) source;
this.desc = desc;
}
public String getJNDI() {
return JNDI;
}
public String getMessage() {
return message;
}
public String getDesc() {
return desc;
}
第三步:抽取事件發佈公共類
/**
* 事件發佈類
*/
@Component
public class EventPublisher implements ApplicationEventPublisherAware {
private static ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public static void publishEvent(ApplicationEvent applicationEvent) {
applicationEventPublisher.publishEvent(applicationEvent);
}
}
第四步:編寫監聽事件
@EventListener有個參數condition進行event屬性過濾。
好比我查的看的有這樣的目前沒研究太多:
@EventListener
@EventListener(condition = "#event.test == 'foo'")(我使用的這個)
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
@EventListener(classes = {BlackListEvent.class})
/**
* 監聽事件:送開通
*/
@Component
public class ProvNotifier {
private static final Logger log = LoggerFactory.getLogger(ProvNotifier.class);
@Autowired
private IProvSvc iProvSvc;
/**
* 監聽送開通的消息
* @param event
*/
@Async
@EventListener( condition= "#event.JNDI == 'sendToProv'")
public void onApplicationEvent(MessageEvent event) {
log.info(" ==>異步事件啓動 onApplicationEvent sendToProv Message:" + event.getMessage());
try {
iProvSvc.sendToProv(event.getMessage(),event.getDesc());
log.info(" ==>送開通成功!");
} catch (Exception e) {
log.error(" %%%%%% onApplicationEvent listener sendToProv:" + e.getMessage());
e.printStackTrace();
}
}
}
第五步:測試
結果:
這是異步的實現基本結束,也能夠根據本身的業務規則實現配置化。
看了不少大神貼也有抄襲多見諒:https://blog.csdn.net/LouisQMei/article/details/79605590
若是有優化還會更細,也請有好的想法指教指教。