Spring 中的Event機制
spring
參考資料:
Additional Capabilities of the ApplicationContext- https://docs.spring.io/spring-framework/reference/6.1/core/beans/context-introduction.html
[[17.行為型 - 觀察者模式 (Observer Pattern)]]
[[Spring IOC 源碼學習總筆記]]
Spring Event
Standard and Custom Events
Event handling in the
ApplicationContextis provided through theApplicationEventclass and theApplicationListenerinterface. If a bean that implements theApplicationListenerinterface is deployed into the context, every time anApplicationEventgets published to theApplicationContext, that bean is notified. Essentially, this is the standard Observer design pattern.
簡而言之 兩點:
- 推送到
ApplicationContext中的事件, 都通知容器中實現(xiàn)ApplicationEvent接口的 bean. this is the standard Observer design pattern它是標準的觀察者模式
觀察者模式和發(fā)布-訂閱模式
觀察者模式的別名有發(fā)布-訂閱(Publish/Subscribe)模式, 我們來看一下觀察者模式與發(fā)布訂閱模式結構上的區(qū)別
- 在設計模式結構上,發(fā)布訂閱模式繼承自觀察者模式,是觀察者模式的一種 實現(xiàn)的變體。
- 在設計模式意圖上,兩者關注點不同,一個關心數(shù)據(jù)源,一個關心的是事件消息。

對比標準的觀察者模式:
- 觀察者模式:數(shù)據(jù)源直接通知訂閱者發(fā)生改變
- 發(fā)布訂閱模式:數(shù)據(jù)源(被觀察者) 告訴第三方(Event Channel) 發(fā)生了改變,第三方(Event Channel)再通知/廣播訂閱者(觀察者) 發(fā)生了改變
Spring 其實基于是發(fā)布訂閱模式, 主要由ApplicationEventMulticaster 管理訂閱者/事件通道/廣播事件;
事件模型的關鍵角色對象
1.ApplicationEvent 事件源(中間傳遞參數(shù))
事件源對象, 在事件中傳遞的中間參數(shù)
org.springframework.context.ApplicationEvent
public abstract class ApplicationEvent extends EventObject {// 它繼承了 java.util.EventObject
/***
定義在 java.util.EventObject 中, 可以通過該方法獲取到事件源對象
public Object getSource() {
return this.source;
}
***/
/**
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
* set to {@link System#currentTimeMillis()}.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
* @see #ApplicationEvent(Object, Clock)
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the time in milliseconds when the event occurred.
* 返回事件發(fā)生時間
* @see #ApplicationEvent(Object)
* @see #ApplicationEvent(Object, Clock)
*/
public final long getTimestamp() {
return this.timestamp;
}
}
2.ApplicationListener 監(jiān)聽器
充當 '觀察者' 角色
org.springframework.context.ApplicationListener
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* 處理事件的方法.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
...
}
3.ApplicationEventPublisher 事件推送器
充當 '被觀察者' 角色
@FunctionalInterface
public interface ApplicationEventPublisher {
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
* <p>If the specified {@code event} is not an {@link ApplicationEvent},
* it is wrapped in a {@link PayloadApplicationEvent}.
* <p>Such an event publication step is effectively a hand-off to the
* multicaster and does not imply synchronous/asynchronous execution
* or even immediate execution at all. Event listeners are encouraged
* to be as efficient as possible, individually using asynchronous
* execution for longer-running and potentially blocking operations.
* @param event the event to publish
* @since 4.2
* @see #publishEvent(ApplicationEvent)
* @see PayloadApplicationEvent
*/
void publishEvent(Object event);
}
4.ApplicationEventMulticaster 事件廣播器
**充當 第三方(Event Channel) 角色, 它通知/廣播 消息給觀察者
管理/廣播/群發(fā)事件, 注冊事件監(jiān)聽器, 管理事件通道, spring 其實最終是委托給該對象廣播事件的
org.springframework.context.event.ApplicationEventMulticaster
/**
* Interface to be implemented by objects that can manage a number of
**/
public interface ApplicationEventMulticaster {
/**
* Add a listener to be notified of all events.
* @param listener the listener to add
* @see #removeApplicationListener(ApplicationListener)
* @see #removeApplicationListeners(Predicate)
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* Add a listener bean to be notified of all events.
* @param listenerBeanName the name of the listener bean to add
* @see #removeApplicationListenerBean(String)
* @see #removeApplicationListenerBeans(Predicate)
*/
void addApplicationListenerBean(String listenerBeanName);
/**
* Remove a listener from the notification list.
* @param listener the listener to remove
* @see #addApplicationListener(ApplicationListener)
* @see #removeApplicationListeners(Predicate)
*/
void removeApplicationListener(ApplicationListener<?> listener);
/**
* Remove a listener bean from the notification list.
* @param listenerBeanName the name of the listener bean to remove
* @see #addApplicationListenerBean(String)
* @see #removeApplicationListenerBeans(Predicate)
*/
void removeApplicationListenerBean(String listenerBeanName);
/**
* Remove all matching listeners from the set of registered
* {@code ApplicationListener} instances (which includes adapter classes
* such as {@link ApplicationListenerMethodAdapter}, e.g. for annotated
* {@link EventListener} methods).
* <p>Note: This just applies to instance registrations, not to listeners
* registered by bean name.
* @param predicate the predicate to identify listener instances to remove,
* e.g. checking {@link SmartApplicationListener#getListenerId()}
* @since 5.3.5
* @see #addApplicationListener(ApplicationListener)
* @see #removeApplicationListener(ApplicationListener)
*/
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
/**
* Remove all matching listener beans from the set of registered
* listener bean names (referring to bean classes which in turn
* implement the {@link ApplicationListener} interface directly).
* <p>Note: This just applies to bean name registrations, not to
* programmatically registered {@code ApplicationListener} instances.
* @param predicate the predicate to identify listener bean names to remove
* @since 5.3.5
* @see #addApplicationListenerBean(String)
* @see #removeApplicationListenerBean(String)
*/
void removeApplicationListenerBeans(Predicate<String> predicate);
/**
* Remove all listeners registered with this multicaster.
* <p>After a remove call, the multicaster will perform no action
* on event notification until new listeners are registered.
* @see #removeApplicationListeners(Predicate)
*/
void removeAllListeners();
/**
* Multicast the given application event to appropriate listeners.
* <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
* if possible as it provides better support for generics-based events.
* @param event the event to multicast
*/
void multicastEvent(ApplicationEvent event);
/**
* Multicast the given application event to appropriate listeners.
* <p>If the {@code eventType} is {@code null}, a default type is built
* based on the {@code event} instance.
* @param event the event to multicast
* @param eventType the type of event (can be {@code null})
* @since 4.2
*/
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
內置的事件類型
官方文檔 - Standard and Custom Events
public class BusinessService implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ContextRefreshedEvent) {
//容器啟動完成事件
}else if(event instanceof ContextClosedEvent) {
//容器關閉事件
excutor.shutdownNow();
log.info("業(yè)務線程池終止");
}
}
}
-
ContextRefreshedEventApplicationContext容器初始化或刷新觸發(fā)該事件。此處說的初始化,是指所有的bean被成功加載,后處理的bean被檢測激活,所有的singleton bean被預初始化,ApplicationContext容器已就緒可用。容器完整可用 -
ContextStartdEvent: 當使用ApplicationContext的子接口ConfigurableApplicationContex接口的start()方法啟動ApplicationContext容器時觸發(fā)該事件。容器管理生命周期的bean實例將獲得一個指定的啟動信號,這在經(jīng)常需要停止后重新啟動的場合比較常見。 -
ContextClossedEvent:當使用ConfigurableApplicationContex接口的close()方法關閉ApplicationContext容器時觸發(fā)該事件。 -
ContextStoppedEvent:當使用ConfigurableApplicationContex接口的stop()方法使ApplicationContext容器停止時觸發(fā)該事件 。此處的“停止”意味著,容器管理生命周期的bean實例將獲得一個指定的停止信號。被停止的spring容器可以再次通過調用start()方法重新啟動。 -
RequestHandledEventWeb:相關的事件,只能應用于使用DispatcherServlet的Web應用中。在使用spring作為前端的MVC控制器時,當spring處理用戶請求結束后,系統(tǒng)會自動觸發(fā)該事件。
自定義事件實例
EventObject 事件定義
定義事件,繼承 ApplicationEvent 的類成為一個事件類
@Data
@ToString
public class OrderProductEvent extends ApplicationEvent {
/** 該類型事件攜帶的信息 */
private String orderId;
public OrderProductEvent(Object source, String orderId) {
super(source);
this.orderId = orderId;
}
}
Listener 監(jiān)聽定義
監(jiān)聽并處理事件,實現(xiàn) ApplicationListener 接口或者使用 @EventListener 注解
@Slf4j
@Component
public class OrderProductListener implements ApplicationListener<OrderProductEvent> {
/** 使用 onApplicationEvent 方法對消息進行接收處理 */
@SneakyThrows
@Override
public void onApplicationEvent(OrderProductEvent event) {
String orderId = event.getOrderId();
long start = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
log.info("{}:校驗訂單商品價格耗時:({})毫秒", orderId, (end - start));
}
}
在 監(jiān)聽器(Listener)
onApplicationEvent中的線程與 發(fā)布(push)線程 不是同一個線程, 它們的ThreadLocal上下文是??完全隔離的??。不?繼承原有事務。
Push 推送定義
如何自定義push事件?
使用 ApplicationEventPublisher 和 ApplicationContext 都可
//@Autowired
//ApplicationEventPublisher publisher;
@Autowired
ApplicationContext applicationContext;
public void publish(String msg){
applicationContext.publishEvent(new OrderProductEvent());
}

浙公網(wǎng)安備 33010602011771號