ApplicationEvent
以及Listener
是Spring為我們提供的一個事件監聽、訂閱的實現,內部實現原理是觀察者設計模式,設計初衷也是為了系統業務邏輯之間的解耦,提高可擴展性以及可維護性。事件發布者并不需要考慮誰去監聽,監聽具體的實現內容是什么,發布者的工作只是為了發布事件而已。
創建Event事件
public class MessageEvent extends ApplicationEvent {/*** 消息體*/private MessageDTO messageDTO;/*** Create a new ApplicationEvent.** @param source the object on which the event initially occurred (never {@code null})*/public MessageEvent(MessageDTO source) {super(source);this.messageDTO = source;}public MessageDTO getMessageDTO() {return messageDTO;}
}
我們自定義事件MessageEvent繼承了ApplicationEvent,繼承后必須重載構造函數,構造函數的參數可以任意指定,其中source參數指的是發生事件的對象,該對象可以在監聽內被獲取。
在Spring內部中有多種方式實現監聽如:@EventListener注解、實現ApplicationListener泛型接口、實現SmartApplicationListener接口等,我們下面來講解下這三種方式分別如何實現。
創建MessageDTO
public class MessageDTO {/*** 消息類型*/private MsgTypeEnum msgType;/*** 消息發出時的時間戳*/private Long syncTime;
}
事件發布
@Service
public class UserService
{@AutowiredApplicationContext applicationContext;public void register(){//../省略其他邏輯//發布事件applicationContext.publishEvent(new MessageEvent(new MessageDTO()));}
}
事件發布是由ApplicationContext對象管控的,我們發布事件前需要注入ApplicationContext對象調用publishEvent方法完成事件發布。
實現監聽
@EventListener
@Service
public class MessageEventService {@EventListenerpublic void notify(MessageEvent messageEvent) {log.info("異步發送消息體:{}", JSON.toJSONString(messageEvent));}
}
ApplicationListener
@Component
public class RegisterListener implements ApplicationListener<MessageEvent>
{/*** 實現監聽*/@Overridepublic void onApplicationEvent(MessageEvent messageEvent) {}
}
SmartApplicationListener實現有序監聽
@Component
public class UserRegisterListener implements SmartApplicationListener
{/*** 該方法返回true&supportsSourceType同樣返回true時,才會調用該監聽內的onApplicationEvent方法* @param aClass 接收到的監聽事件類型* @return*/@Overridepublic boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {//只有MessageEvent監聽類型才會執行下面邏輯return aClass == MessageEvent.class;}/*** 該方法返回true&supportsEventType同樣返回true時,才會調用該監聽內的onApplicationEvent方法* @param aClass* @return*/@Overridepublic boolean supportsSourceType(Class<?> aClass) {//只有在UserService內發布的MessageEvent事件時才會執行下面邏輯return aClass == UserService.class;}/*** supportsEventType & supportsSourceType 兩個方法返回true時調用該方法執行業務邏輯* @param applicationEvent 具體監聽實例,這里是UserRegisterEvent*/@Overridepublic void onApplicationEvent(ApplicationEvent applicationEvent) {//轉換事件類型MessageEvent messageEvent = (MessageEvent) applicationEvent;}/*** 同步情況下監聽執行的順序* @return*/@Overridepublic int getOrder() {return 0;}
}
SmartApplicationListener接口繼承了全局監聽ApplicationListener,并且泛型對象使用的ApplicationEvent來作為全局監聽,可以理解為使用SmartApplicationListener作為監聽父接口的實現,監聽所有事件發布。
既然是監聽所有的事件發布,那么SmartApplicationListener接口添加了兩個方法supportsEventType、supportsSourceType來作為區分是否是我們監聽的事件,只有這兩個方法同時返回true時才會執行onApplicationEvent方法。
可以看到除了上面的方法,還提供了一個getOrder方法,這個方法就可以解決執行監聽的順序問題,return的數值越小證明優先級越高,執行順序越靠前。
如果說我們不希望在執行監聽時等待監聽業務邏輯耗時,發布監聽后立即要對接口或者界面做出反映,我們該怎么做呢?
?使用@Async實現異步監聽
@Aysnc其實是Spring內的一個組件,可以完成對類內單個或者多個方法實現異步調用,這樣可以大大的節省等待耗時。內部實現機制是線程池任務ThreadPoolTaskExecutor,通過線程池來對配置@Async的方法或者類做出執行動作。
線程任務池配置
我們創建一個ListenerAsyncConfiguration,并且使用@EnableAsync注解開啟支持異步處理,具體代碼如下所示:
@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer
{/*** 獲取異步線程池執行對象* @return*/@Overridepublic Executor getAsyncExecutor() {//使用Spring內置線程池任務對象ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//設置線程池參數taskExecutor.setCorePoolSize(5);taskExecutor.setMaxPoolSize(10);taskExecutor.setQueueCapacity(25);taskExecutor.initialize();return taskExecutor;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return null;}
}
我們自定義的監聽異步配置類實現了AsyncConfigurer接口并且實現內getAsyncExecutor方法以提供線程任務池對象的獲取。
我們只需要在異步方法上添加@Async注解就可以實現方法的異步調用
@Service
public class MessageEventService {@EventListener@Asyncpublic void notify(MessageEvent messageEvent) {log.info("異步發送消息體:{}", JSON.toJSONString(messageEvent));}
}