前言
spring的事件驅動模型,想必大家都比較熟,今天就來水一期,如何使用事件條件來進行事件觸發。直接上示例
正文
注: 本示例主要模擬當使用者註冊,傳送阿里雲簡訊,模擬下單,傳送騰訊雲簡訊,模擬傳送簡訊的邏輯,下放到事件監聽裡面做
1、模擬建立阿里雲簡訊
public class AliyunSmsService implements SmsService {
@Override
public void sendSms(String phone, String content) {
System.out.printf("%s->使用阿里雲簡訊【%s】傳送成功!%n",phone,content);
}
}
2、建立簡訊事件
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SmsEvent {
private String phone;
private String content;
private SmsEnums smsEnums;
}
3、模擬監聽阿里雲簡訊事件
@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、模擬使用者註冊
@Service
@RequiredArgsConstructor
public class UserService {
private final ApplicationContext applicationContext;
public void mockRegister(String username,String phone){
System.out.println("使用者註冊成功,使用者名稱:"+username);
SmsEvent smsEvent = SmsEvent.builder().phone(phone).content("歡迎註冊").smsEnums(SmsEnums.ALIYUN).build();
applicationContext.publishEvent(smsEvent);
}
}
注: 模擬下單和使用者註冊,流程基本一樣,就不貼程式碼了
5、測試驗證
@Test
public void testAliyunSms(){
userService.mockRegister("lybgeek","13800000001");
}
@Test
public void testTencentSms(){
orderService.mockOrder("lybgeek","13800000002");
}
測試結果
a、當模擬使用者註冊時,控制檯輸出
會發現只會觸發阿里雲簡訊事件的傳送
b、當模擬下單時,控制檯輸出
會發現只會觸發騰訊雲簡訊事件的傳送
實現核心邏輯
透過在@EventListener的condition配置spel條件表示式,當condition為空時,預設事件都會觸發,如果有指定相應的spel條件表示式,則會按條件表示式,再進行一層過濾
具體原始碼片段
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");
}
}
}
總結
看完也許有朋友會說,我直接在監聽類方法裡,寫if-else也可以達到效果啊,為啥那麼麻煩。如果業務沒那麼複雜的話,可以這麼做,但是我們本身使用事件就是為了解耦,如果在事件監聽裡面寫一堆if-else,一來職責不夠單一,二來我們更提倡對修改關閉,對擴充套件開放
demo連結
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-event-condition