引用: https://juejin.im/post/5d93fa78f265da5b991d5133
談到Spring 事件驅動模型,我想大家都不陌生,事件驅動模型,通常也可以說是觀察者設計模式。
java本身也自帶了對事件驅動的支持,但是大部分都是用於我們的客戶端開發,比如GUI ,Swing這些,而Spring 則在java的基礎上,擴展了對事件驅動的支持。
廢話不多說,直接擼代碼。
事件驅動編程
自定義ApplicationEvent
我們新建一個類NotifyEvent 繼承ApplicationEvent,用於封裝我們事件額外的信息,這裏則是String類型的msg,用於記錄詳細的事件內容。
public class NotifyEvent extends ApplicationEvent {
@Getter
private String msg;
public NotifyEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
自定義事件發佈者Publisher
NotifyPublisher用於我們事件的發佈工作,該類實現了ApplicationContextAware
並重寫了setApplicationContext 方法,這一步的目的是可以獲取我們Spring的應用上下文,因爲事件的發佈是需要應用上下文來做的.
@Component
@Slf4j
public class NotifyPublisher implements ApplicationContextAware {
private ApplicationContext ctx; //應用上下文
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ctx= applicationContext;
}
public void publishEvent(int type, String json) {
ctx.publishEvent(new NotifyEvent(type, json));
}
}
自定義事件訂閱者Listener
最後一步就是實現一個類作爲事件的訂閱者啦,當事件發佈時,會通知訂閱者,然後訂閱者做相關的處理,比如新用戶註冊發送事件自動發送歡迎郵件等等。
@Component
@Slf4j
//指定具體的事件類型: E extends ApplicationEvent
public class NotifyListener implements ApplicationListener<NotifyEvent> {
@Override
public void onApplicationEvent(NotifyEvent event) {
log.info("收到事件{}",event.getMsg());
}
}
@EventListener
Spring 4.2 版本更新的EventListener,可以很方便幫助我們實現事件與方法的綁定,只需要在目標方法上加上EventListener即可。
@Component
public class MqListener {
@EventListener
//參數NotifyEvent ,當有NotifyEvent 類型的事件發生時,交給sayHello方法處理
public void sayHello(NotifyEvent notifyEvent){
log.info("收到事件{}",event.getMsg());
}
}
測試
public class AuthenticationCenterApplication implements CommandLineRunner {
//略...
@Autowired
private NotifyPublisher mqPublisher;
@Override
public void run(String... args) throws Exception {
AtomicInteger loop = new AtomicInteger(1);
while (loop.get() < 10) {
mqPublisher.publishEvent(1, "nihao_" + loop.getAndIncrement());
TimeUnit.SECONDS.sleep(1);
}
}
}
後臺打印結果:
每隔一秒種打印一次數據。
但是可以看到上述的執行內容,全部是由main
線程執行的。
異步事件驅動編程
Spring 也提供了@Async 註解來實現異步事件的消費。用起來也很簡單,只需要在
@EventListener
上加上@Async
- 或者
onApplicationEvent
方法上添加@Async
springboot開啓@EnableAsync 即可支持異步。
@EnableAsync
public class AuthenticationCenterApplication implements CommandLineRunner {
}
執行結果:
自定義線程池
Springboot默認的異步線程池名爲"taskExecutor":
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor, 可以通過注入
java.util.concurrent.Executor`進行覆蓋:
@Bean
public Executor taskExecutor(){
return new ThreadPoolExecutor(2,
4,
1000,
TimeUnit.SECONDS,
new ArrayBlockingQueue(5),
new UserThreadFactory("myAysnc")
);
}
static class UserThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
UserThreadFactory(String whatFeatureOfGroup) {
namePrefix = whatFeatureOfGroup + "-pool-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement();
Thread thread = new Thread(null, task, name,0);
return thread;
}
}
打印結果: