前言
spring的事件驅(qū)動(dòng)模型荚恶,想必大家都比較熟,今天就來(lái)水一期功舀,如何使用事件條件來(lái)進(jìn)行事件觸發(fā)。直接上示例
正文
注: 本示例主要模擬當(dāng)用戶注冊(cè)身弊,發(fā)送阿里云短信辟汰,模擬下單,發(fā)送騰訊云短信阱佛,模擬發(fā)送短信的邏輯帖汞,下放到事件監(jiān)聽(tīng)里面做
1、模擬創(chuàng)建阿里云短信
public class AliyunSmsService implements SmsService {
@Override
public void sendSms(String phone, String content) {
System.out.printf("%s->使用阿里云短信【%s】發(fā)送成功凑术!%n",phone,content);
}
}
2翩蘸、創(chuàng)建短信事件
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SmsEvent {
private String phone;
private String content;
private SmsEnums smsEnums;
}
3、模擬監(jiān)聽(tīng)阿里云短信事件
@RequiredArgsConstructor
public class AliyunSmsListener {
private final AliyunSmsService aliyunSmsService;
@EventListener(condition = "#smsEvent.smsEnums.name().equalsIgnoreCase('aliyun')")
public void listener(SmsEvent smsEvent){
aliyunSmsService.sendSms(smsEvent.getPhone(),smsEvent.getContent());
}
}
4淮逊、模擬用戶注冊(cè)
@Service
@RequiredArgsConstructor
public class UserService {
private final ApplicationContext applicationContext;
public void mockRegister(String username,String phone){
System.out.println("用戶注冊(cè)成功催首,用戶名:"+username);
SmsEvent smsEvent = SmsEvent.builder().phone(phone).content("歡迎注冊(cè)").smsEnums(SmsEnums.ALIYUN).build();
applicationContext.publishEvent(smsEvent);
}
}
注: 模擬下單和用戶注冊(cè),流程基本一樣泄鹏,就不貼代碼了
5郎任、測(cè)試驗(yàn)證
@Test
public void testAliyunSms(){
userService.mockRegister("lybgeek","13800000001");
}
@Test
public void testTencentSms(){
orderService.mockOrder("lybgeek","13800000002");
}
測(cè)試結(jié)果
a、當(dāng)模擬用戶注冊(cè)時(shí)备籽,控制臺(tái)輸出
會(huì)發(fā)現(xiàn)只會(huì)觸發(fā)阿里云短信事件的發(fā)送
b舶治、當(dāng)模擬下單時(shí),控制臺(tái)輸出
會(huì)發(fā)現(xiàn)只會(huì)觸發(fā)騰訊云短信事件的發(fā)送
實(shí)現(xiàn)核心邏輯
通過(guò)在@EventListener的condition配置spel條件表達(dá)式车猬,當(dāng)condition為空時(shí)霉猛,默認(rèn)事件都會(huì)觸發(fā),如果有指定相應(yīng)的spel條件表達(dá)式诈唬,則會(huì)按條件表達(dá)式韩脏,再進(jìn)行一層過(guò)濾
具體源碼片段
org.springframework.context.event.ApplicationListenerMethodAdapter#processEvent
private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
if (args == null) {
return false;
}
String condition = getCondition();
if (StringUtils.hasText(condition)) {
Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
return this.evaluator.condition(
condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
}
return true;
}
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
總結(jié)
看完也許有朋友會(huì)說(shuō),我直接在監(jiān)聽(tīng)類方法里铸磅,寫if-else也可以達(dá)到效果啊赡矢,為啥那么麻煩。如果業(yè)務(wù)沒(méi)那么復(fù)雜的話阅仔,可以這么做吹散,但是我們本身使用事件就是為了解耦,如果在事件監(jiān)聽(tīng)里面寫一堆if-else八酒,一來(lái)職責(zé)不夠單一空民,二來(lái)我們更提倡對(duì)修改關(guān)閉,對(duì)擴(kuò)展開(kāi)放
demo鏈接
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-event-condition