廢話前言:
首先說一下我為什么使用事件,比如現在創建一個訂單但是我創建成功后要給客戶發送一條短信和一個郵件提醒,本身沒創建訂單一系列操作就需要很多時間但是我還要去發送短信和郵件,期間還要調用其它服務來實現耗時比較長達不到客戶的滿意度,所以使用的方式可以說一下:
1:activeMQ(異步)
2:使用spring事件監聽(同步+異步)
下面我們只說第二種方式
/**
* 自定義管理事件
*/
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;
}
第二:定義一個監聽
/**
* 測試用自定義監聽器,監聽事件為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
如果有優化還會更細,也請有好的想法指教指教。