聊聊spring專案如何根據事件條件進行事件分發

linyb极客之路發表於2024-10-29

前言

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

相關文章