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 ApplicationContext is provided through the ApplicationEvent class and the ApplicationListener interface. If a bean that implements the ApplicationListener interface is deployed into the context, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified. Essentially, this is the standard Observer design pattern.

简而言之 两点:

  1. 推送到 ApplicationContext 中的事件, 都通知容器中实现 ApplicationEvent 接口的 bean.
  2. this is the standard Observer design pattern 它是标准的观察者模式

观察者模式和发布-订阅模式

观察者模式的别名有发布-订阅(Publish/Subscribe)模式, 我们来看一下观察者模式与发布订阅模式结构上的区别

  • 在设计模式结构上,发布订阅模式继承自观察者模式,是观察者模式的一种 实现的变体。
  • 在设计模式意图上,两者关注点不同,一个关心数据源,一个关心的是事件消息。

截图_2025-11-04_22-24-18

对比标准的观察者模式:

  • 观察者模式:数据源直接通知订阅者发生改变
  • 发布订阅模式:数据源(被观察者) 告诉第三方(Event Channel) 发生了改变,第三方(Event Channel)再通知/广播订阅者(观察者) 发生了改变

Spring 其实基于是发布订阅模式, 主要由ApplicationEventMulticaster 管理订阅者/事件通道/广播事件;

事件模型的关键角色对象

1.ApplicationEvent 事件源(中间传递参数)

事件源对象, 在事件中传递的中间参数

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.  
	* 返回事件发生时间
	* @see #ApplicationEvent(Object)  
	* @see #ApplicationEvent(Object, Clock)  
	*/  
	public final long getTimestamp() {  
		return this.timestamp;  
	}
	
}

2.ApplicationListener 监听器

充当 '观察者' 角色

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) 角色, 它通知/广播 消息给观察者

管理/广播/群发事件, 注册事件监听器, 管理事件通道, 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
Built-in Events

Event Explanation
ContextRefreshedEvent Published when the ApplicationContext is initialized or refreshed (for example, by using the refresh() method on the ConfigurableApplicationContext interface). Here, “initialized” means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such “hot” refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not.
ContextStartedEvent Published when the ApplicationContext is started by using the start() method on the ConfigurableApplicationContext interface. Here, “started” means that all Lifecycle beans receive an explicit start signal. Typically, this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart (for example, components that have not already started on initialization).
ContextStoppedEvent Published when the ApplicationContext is stopped by using the stop() method on the ConfigurableApplicationContext interface. Here, “stopped” means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call.
ContextClosedEvent Published when the ApplicationContext is being closed by using the close() method on the ConfigurableApplicationContext interface or via a JVM shutdown hook. Here, "closed" means that all singleton beans will be destroyed. Once the context is closed, it reaches its end of life and cannot be refreshed or restarted.
RequestHandledEvent A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications that use Spring’s DispatcherServlet.
ServletRequestHandledEvent A subclass of RequestHandledEvent that adds Servlet-specific context information.
  • ContextRefreshedEvent ApplicationContext容器初始化或刷新触发该事件。此处说的初始化,是指所有的bean被成功加载,后处理的bean被检测激活,所有的singleton bean被预初始化,ApplicationContext容器已就绪可用。容器完整可用

  • ContextStartdEvent: 当使用ApplicationContext的子接口ConfigurableApplicationContex接口的start()方法启动ApplicationContext容器时触发该事件。容器管理生命周期的bean实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见。

  • ContextClossedEvent:当使用ConfigurableApplicationContex接口的close()方法关闭ApplicationContext容器时触发该事件。

  • ContextStoppedEvent:当使用ConfigurableApplicationContex接口的stop()方法使ApplicationContext容器停止时触发该事件 。此处的“停止”意味着,容器管理生命周期的bean实例将获得一个指定的停止信号。被停止的spring容器可以再次通过调用start()方法重新启动。

  • RequestHandledEventWeb:相关的事件,只能应用于使用DispatcherServlet的Web应用中。在使用spring作为前端的MVC控制器时,当spring处理用户请求结束后,系统会自动触发该事件。

public class BusinessService implements ApplicationListener {
	@Override  
	public void onApplicationEvent(ApplicationEvent event) {  
	    if(event instanceof ContextRefreshedEvent) {  
		    //容器启动完成事件  
		}else if(event instanceof ContextClosedEvent) {  
			//容器关闭事件
		    excutor.shutdownNow();  
		    log.info("业务线程池终止");  
		}
	}
}

自定义事件实例

EventObject 事件定义

定义事件,继承 ApplicationEvent 的类成为一个事件类

@Data  
@ToString  
public class OrderProductEvent extends ApplicationEvent {  
  
  /** 该类型事件携带的信息 */  
  private String orderId;  
  
  public OrderProductEvent(Object source, String orderId) {  
    super(source);  
    this.orderId = orderId;  
  }  
}

Listener 监听定义

监听并处理事件,实现 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));  
  }  
}

在 监听器(Listener) onApplicationEvent 中的线程与 发布(push)线程 不是同一个线程, 它们的 ThreadLocal上下文是​​完全隔离的​​。不​继承原有事务。

Push 推送定义

如何自定义push事件?
使用 ApplicationEventPublisherApplicationContext 都可

//@Autowired
//ApplicationEventPublisher publisher;

@Autowired
ApplicationContext applicationContext;

public void publish(String msg){
	applicationContext.publishEvent(new OrderProductEvent());
}

相关源码

使用多播器广播事件

org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)

/**
 * Publish the given event to all listeners.
 * <p>This is the internal delegate that all other {@code publishEvent}
 * methods refer to. It is not meant to be called directly but rather serves
 * as a propagation mechanism between application contexts in a hierarchy,
 * potentially overridden in subclasses for a custom propagation arrangement.
 * @param event the event to publish (may be an {@link ApplicationEvent}
 * or a payload object to be turned into a {@link PayloadApplicationEvent})
 * @param typeHint the resolved event type, if known.
 * The implementation of this method also tolerates a payload type hint for
 * a payload object to be turned into a {@link PayloadApplicationEvent}.
 * However, the recommended way is to construct an actual event object via
 * {@link PayloadApplicationEvent#PayloadApplicationEvent(Object, Object, ResolvableType)}
 * instead for such scenarios.
 * @since 4.2
 * @see ApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)
 */
protected void publishEvent(Object event, @Nullable ResolvableType typeHint) {
	Assert.notNull(event, "Event must not be null");
	ResolvableType eventType = null;

	// Decorate event as an ApplicationEvent if necessary
	ApplicationEvent applicationEvent;
	if (event instanceof ApplicationEvent applEvent) {
		applicationEvent = applEvent;
		eventType = typeHint;
	}
	else {
		ResolvableType payloadType = null;
		if (typeHint != null && ApplicationEvent.class.isAssignableFrom(typeHint.toClass())) {
			eventType = typeHint;
		}
		else {
			payloadType = typeHint;
		}
		applicationEvent = new PayloadApplicationEvent<>(this, event, payloadType);
	}
	// Determine event type only once (for multicast and parent publish)
	if (eventType == null) {
		eventType = ResolvableType.forInstance(applicationEvent);
		if (typeHint == null) {
			typeHint = eventType;
		}
	}
	// Multicast right now if possible - or lazily once the multicaster is initialized
	if (this.earlyApplicationEvents != null) {
		this.earlyApplicationEvents.add(applicationEvent);
	}
	else if (this.applicationEventMulticaster != null) {
		/**
		 * 拿到当前的多播器 applicationEventMulticaster
		 * 这个是在初始化多播器的时候 初始化的 {@link AbstractApplicationContext#initApplicationEventMulticaster()}
		 * SimpleApplicationEventMulticaster
		 */
		this.applicationEventMulticaster.multicastEvent(applicationEvent, eventType);
	}

	/**
	 * 如果存在父context;
	 * 父context也需要发布
	 */
	// Publish event via parent context as well...
	if (this.parent != null) {
		if (this.parent instanceof AbstractApplicationContext abstractApplicationContext) {
			abstractApplicationContext.publishEvent(event, typeHint);
		}
		else {
			this.parent.publishEvent(event);
		}
	}
}

多播器的初始化

org.springframework.context.support.AbstractApplicationContext#refresh


@Override
	public void refresh() throws BeansException, IllegalStateException {
		// 容器刷新, 执行时, 需要锁住
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			/**
			 * 一, (ApplicationContex)预准备工作;
			 */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			/**
			 * 二, 获取一个新的 BeanFactory;
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/**
			 * 三,(BeanFactory)预准备工作;
			 */
			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				/**
				 * 四, beanFactory 已经准备好了, 给子类(Context)预留一个扩展点; (这里是空实现)
				 */
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

				// Invoke factory processors registered as beans in the context.
				/**
				 * 五, 调用 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor;
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				/**
				 *  六,注册 BeanPostProcessor (BPP)处理器;
				 */
				registerBeanPostProcessors(beanFactory);

				beanPostProcess.end();

				// Initialize message source for this context.
				/**
				 * 七,初始化I18N国际化, 消息源;
				 */
				initMessageSource();

				// Initialize event multicaster for this context.
				/**
				 * 八, 初始化 事件多播器;
				 * 1. 如果 beanFactory 中包含名称为 applicationEventMulticaster 的bean定义, 则使用这个Bean作为事件多播器;
				 *   如果不包含则创建 SimpleApplicationEventMulticaster作为事件多播器;
				 * 2.创建SimpleApplicationEventMulticaster其实就是初始化了一个,用于存放/管理 ApplicationListener 监听器(观察者)的类, 并注册到 beanFactory
				 * 	主要是 {@link org.springframework.context.event.AbstractApplicationEventMulticaster#defaultRetriever}
				 */
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				/**
				 * 九, 给子类(Context)留下一个扩展点
				 */
				onRefresh();

				// Check for listener beans and register them.
				/**
				 * 十,向多播器注册监听器;
				 */
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				/**
				 * 十一,实例化剩下的所有单例bean
				 */
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				/**
				 * 十二, 完成刷新
				 */
				finishRefresh();
			}

			catch (RuntimeException | Error ex ) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
			finally {
				contextRefresh.end();
			}
		}
	}


org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster

/**
	 * Initialize the ApplicationEventMulticaster.
	 * Uses SimpleApplicationEventMulticaster if none defined in the context.
	 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
	 */
	protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		/**
		 * 如果 beanFactory 中包含名称为 APPLICATION_EVENT_MULTICASTER_BEAN_NAME的bean定义, 则使用这个 ApplicationEventMulticaster 作为 事件多播器
		 * 如果不包含则创建 SimpleApplicationEventMulticaster作为事件多播器;
		 */
		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 {
			/**
			 * 创建 SimpleApplicationEventMulticaster 作为默认的事件多播器 (Event Channel)
			 * 注意 applicationEventMulticaster 属性, 在注册监听器的时候, 直接用到它
			 *  1. 其实就是初始化了一个 用于存放/管理 ApplicationListener 监听器(观察者)的类. 在Spring 事件机制中, 在容器发布事件时
			 *  `applicationContext.publishEvent(new ObjectEvent());`  就是用它过滤发布事件的
			 *  @see org.springframework.context.event.AbstractApplicationEventMulticaster#defaultRetriever
			 */
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			/**
			 * 将其注册到 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() + "]");
			}
		}
	}
posted @ 2025-11-04 22:25  daidaidaiyu  阅读(19)  评论(0)    收藏  举报