Spring 事件機制
概念
在一個完整的事件體系中、存在以下的角色
- 事件:描述發生了什麼事情、比如說請求處理完成、Spring 容器刷新完畢
- 事件源:事件的產生者、任何一個事件都必須有一個事件源。比如請求處理完成的事件源就是
DispatcherServlet
、Spring 容器刷新完畢的事件源就是ApplicationContext
- 事件廣播器:事件和事件監聽器的橋樑、負責把事件通知給事件監聽器
- 事件監聽器:監聽事件的發生、可以在監聽器中做一些處理
Spring 事件
我們常見的事件可能就是 ApplicationContextEvent
、它的子類 ContextRefreshedEvent
是我們常見的事件類型、在 Spring 將所有非延遲加載的 bean 實例化之後發佈。
再來看看 Spring 事件的體系結構
Spring 監聽器
事件廣播器
ApplicationContext 對事件的支持
ApplicationEventPublisher 這個是 Spring 提供給用戶使用的一個事件發佈器啊、真正實現發佈功能還是委託給上面的 ApplicationEventMulticaster 去實現的。
Spring 提供了 ApplicationEventPublisherAware 讓用戶可以去獲取這個發佈器進行事件發佈。
使用方式
Spring 提供了兩種方式
- 實現 ApplicationListener 接口
- 使用註解 @EventListener
註解的實現源碼
我們直接看到 EventListenerMethodProcessor 該類實現了接口 SmartInitializingSingleton 接口、該接口會在 Spring 初始化完所有的非延遲加載的 bean 之後被調用。
public interface SmartInitializingSingleton {
/**
* Invoked right at the end of the singleton pre-instantiation phase,
* with a guarantee that all regular singleton beans have been created
* already. {@link ListableBeanFactory#getBeansOfType} calls within
* this method won't trigger accidental side effects during bootstrap.
* <p><b>NOTE:</b> This callback won't be triggered for singleton beans
* lazily initialized on demand after {@link BeanFactory} bootstrap,
* and not for any other bean scope either. Carefully use it for beans
* with the intended bootstrap semantics only.
*/
void afterSingletonsInstantiated();
}
其實實現邏輯非常簡單
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
找出所有被註解修飾的方法、然後分別創建一個對應的 ApplicationListener、收到事件後反射調用該方法。
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");
}
}
}
監聽器調用的先後順序
我們可以在 AbstractApplicationEventMulticaster#retrieveApplicationListeners 中看到是支持我們指定監聽器的順序的、Spring 很多涉及順序的都可以使用
- 實現 Ordered 接口
- 實現 PriorityOrdered 接口
- 使用 @Ordered 接口
異步調用監聽器
默認情況下、Spring 創建的事件廣播器是採用同步方式調用通知監聽器的、我們可以設置或者替換 Spring 默認的監聽器來達到異步調用的目的、當然也可以擴展、根據事件的不同採用同步或者異步的方式、而不是單一的要麼所有同步要麼所有異步
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
Spring refresh 之前回初始化事件傳播器
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
替換原來的事件傳播器
@Component("applicationEventMulticaster")
public class TestEventMulticaster extends SimpleApplicationEventMulticaster {
}