spring中多播器与监听器
参考文章:https://www.cnblogs.com/nijunyang/p/12339757.html
自定义多播器+异步通知:https://blog.csdn.net/pengweismile/article/details/92363266
观察者模式引申:https://blog.csdn.net/weixin_42182146/article/details/118873865
首先来说,spring中的监听机制运用的设计模式为 观察者模式;
那么简易的观察者模式有两个主要角色:
观察者与被观察者;
被观察者主动通知观察者,观察者做出相应的响应;因此,被观察者维护观察者的列表;
spring中使用多播器,监听器,事件来完成监听机制;
多播器-ApplicationEventMulticaster,监听器-ApplicationListener,事件-ApplicationEvent
三者的关系类似于:
多播器ApplicationEventMulticaster 维护了一系列监听器ApplicationListener 列表;(这只是个描述,实际上并不是直接维护了一个ApplicationListener列表)。
ApplicationEventMulticaster 发送 事件ApplicationEvent;监听器接收到事件ApplicationEvent之后,做出响应,即调用onApplicationEvent(E event)方法;
类比于观察者模式角色,则
观察者:监听器ApplicationListener ,需要自定义一个响应方法体;
被观察者:IOC容器,IOC容器委托ApplicationEventMulticaster发布事件;发布事件的动作就是主动通知观察者的动作。
spring中如何简易实现自定义监听机制:
实现效果:发送‘”饿了事件“,spring响应买零食;发送“”渴了事件“”,spring响应买饮料
1,自定义需要监听的事件,extends ApplicationContextEvent
此处自定义了两个事件,
public abstract class MyEvent extends ApplicationContextEvent { // 事件描述 private String description; public MyEvent(ApplicationContext source, String description) { super(source); this.description = description; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
//自定义事件 public class HungryEvent extends MyEvent { public HungryEvent(ApplicationContext source, String description) { super(source, description); } }
/** * 自定义事件 */ public class ThirstyEvent extends MyEvent { public ThirstyEvent(ApplicationContext source, String description) { super(source, description); } }
2,自定义监听器
2.1,implements ApplicationListener<Event>,重写 onApplicationEvent 方法;
/** * 自定义监听器,对事件做出相应 * 泛型为此监听器的监听类型 */ @Component public class MyListener implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent event) { if("hungry".equals(event.getDescription())){ System.out.println("监听到hungry,买零食"); }else if("thirsty".equals(event.getDescription())){ System.out.println("监听到thirsty,买饮料"); } } }
2.2,使用注解 @Component + @EventListener,该方式比较简单灵活;
/** * @Component + @EventListener 注解,实现自定义监听方法 * 两个注解都必须有 */ @Component public class MyListener_02 { /** * 参数为监听的事件类型 * 方法名可以随意,不一定需要固定的方案 * @param event */ @EventListener public void handleMyEvent(MyEvent event){ System.out.println("监听到 "+event.getDescription()); } }
3,启动spring服务,发送事件;
@ComponentScan public class ListenerTest_01 { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ListenerTest_01.class); // 发送事件 ctx.publishEvent(new HungryEvent(ctx,"hungry")); ctx.publishEvent(new ThirstyEvent(ctx,"thirsty"));
}
}
运行结果:
监听到hungry,买零食
监听到thirsty,买饮料
当一个事件同时使用两种方式设置了监听器,运行结果:
监听到 hungry
监听到hungry,买零食
监听到 thirsty
监听到thirsty,买饮料
由此,就是实现了一个最简单的spring监听机制;并且,注解配置的监听器 优于 接口先执行;
上述代码,并没有自定义多播器ApplicationEventMulticaster,也没有显式将监听器ApplicationListener关联ApplicationEventMulticaster,
实际上,如果没有自定义ApplicationEventMulticaster,spring会使用默认的SimpleApplicationEventMulticaster;
通过@Component注解将自定义的监听器交给spring管理之后,spring初始化时会自动将自定义的ApplicationListener加入到多播器的监听器列表中;
源码部分:
ApplicationEventMulticaster 是一个接口,可以发现他的功能就是:
1,添加/删除ApplicationListener;
2,发布事件
/** * Interface to be implemented by objects that can manage a number of * {@link ApplicationListener} objects and publish events to them. * * <p>An {@link org.springframework.context.ApplicationEventPublisher}, typically * a Spring {@link org.springframework.context.ApplicationContext}, can use an * {@code ApplicationEventMulticaster} as a delegate for actually publishing events. */ public interface ApplicationEventMulticaster { /** * Add a listener to be notified of all events. * @param listener the listener to add */ void addApplicationListener(ApplicationListener<?> listener); /** * Add a listener bean to be notified of all events. * @param listenerBeanName the name of the listener bean to add */ void addApplicationListenerBean(String listenerBeanName); /** * Remove a listener from the notification list. * @param listener the listener to remove */ void removeApplicationListener(ApplicationListener<?> listener); /** * Remove a listener bean from the notification list. * @param listenerBeanName the name of the listener bean to remove */ void removeApplicationListenerBean(String listenerBeanName); /** * 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. */ 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); }
ApplicationListener也是一个接口,泛型<E extends ApplicationEvent>决定了该监听器监听的事件类型;
他只有一个方法,该方法当监听到事件发生之后执行;
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
ApplicationContextEvent 为抽象类,自定义事件就会继承该类;
public abstract class ApplicationContextEvent extends ApplicationEvent { /** * Create a new ContextStartedEvent. * @param source the {@code ApplicationContext} that the event is raised for * (must not be {@code null}) */ public ApplicationContextEvent(ApplicationContext source) { super(source); } /** * Get the {@code ApplicationContext} that the event was raised for. */ public final ApplicationContext getApplicationContext() { return (ApplicationContext) getSource(); } }
spring启动的时候是如何初始化多播器的呢?
以下参考:https://blog.csdn.net/lewismago/article/details/113534310
众所周知,spring初始化的核心方法为:org.springframework.context.support.AbstractApplicationContext#refresh()
//org.springframework.context.support.AbstractApplicationContext#refresh // 十三个方法调用 public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { // 1,准备工作,设置容器的启动时间,设置活跃状态等等, // 获取Environment对象加载到Spring环境中,准备监听器和事件的集合对象 this.prepareRefresh(); // 2,创建容器对象:DefaultListableBeanFactory // 加载xml配置文件的bean到该工程,最重要的就是BeanDefinition // lorg.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // 3,beanFactory的准备工作,对beanFactory的属性进行填充 // 设置忽略的依赖等等,addBeanPostProcessor()等等 // 例如:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); this.prepareBeanFactory(beanFactory); try { // 4,留给子类做扩展的额外方法,一般不做扩展 this.postProcessBeanFactory(beanFactory); // 5,调用BeanFactoryPostProcessor方法,此处可以修改BeanDefinition // ???private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();什么情况下add的? // BeanDefinitionRegistryPostProcessor !! // Invoke factory processors registered as beans in the context. // Instantiate and invoke all registered BeanFactoryPostProcessor beans,respecting explicit order if given. this.invokeBeanFactoryPostProcessors(beanFactory); // 6,注册bean处理器,这里只是注册功能,并没有调用 this.registerBeanPostProcessors(beanFactory); // 7,为上下文初始化Message源,即不同语言的消息体国际化处理 // 主要涉及到 "messageSource", MessageSource.class 的处理 this.initMessageSource(); // 8,初始化事件监听器多路广播器,一般情况下为默认值 // this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); // Initialize event multicaster for this context. this.initApplicationEventMulticaster(); // 9,留给子类初始化其他bean this.onRefresh(); // 10,在所有注册bean中寻找linstner bean,注册到多播器中 // Check for listener beans and register them. this.registerListeners(); // 11,实例化剩下的非懒加载的单例对象 // 此实例化操作实际上包含了实例化和初始化整个操作 // beanFactory.preInstantiateSingletons(); // 实际会调用的是 >org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons // 最终会调用.getBean();方法 >org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) this.finishBeanFactoryInitialization(beanFactory); // 12,完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,发送ContextRefreshEvent通知 // Last step: publish corresponding event. this.finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 13, // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { this.resetCommonCaches(); } } }
整个初始化方法,涉及到spring监听机制的步骤大概如下:
1,初始化多播器 initApplicationEventMulticaster();
2,将注册的bean中寻找listener,并将他们关联到多播器中 registerListeners();
3,发布事件 this.finishRefresh();
1,初始话多播器:
/** * Name of the ApplicationEventMulticaster bean in the factory. * If none is supplied, a default SimpleApplicationEventMulticaster is used. * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster"; /** * Initialize the ApplicationEventMulticaster. * Uses SimpleApplicationEventMulticaster if none defined in the context. * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ protected void initApplicationEventMulticaster() { // 获取当前beanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 如果存在自定义的“applicationEventMulticaster”,就使用自定义的多播器 // beanName一定要使用‘applicationEventMulticaster’ 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 extends AbstractApplicationEventMulticaster // Absxxxx 存在private final ListenerRetriever defaultRetriever,里保存了listener的引用 // this.defaultRetriever.applicationListeners.add(listener); 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() + "]"); } } }
2,注册listeners + 发布早期事件;
/** * Add beans that implement ApplicationListener as listeners. * Doesn't affect other listeners, which can be added without being beans. */ protected void registerListeners() { // Register statically specified listeners first. // this.applicationListeners的get方法,遍历程序中已经存在的监听器,并将监听器加入到多播器中 for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // addAddApplicationListener(),addApplicationListenerBean()方法其实调用的 // org.springframework.context.event.AbstractApplicationEventMulticaster#addApplicationListener // 其实AbstractApplicationEventMulticaster并不直接存在applicationListeners属性,而是执行this.defaultRetriever.applicationListeners.add(listener); // 该属性为private final ListenerRetriever defaultRetriever = new ListenerRetriever(false); // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! // 从容器中获取所有实现了ApplicationListener接口的bd,并将beaName加入到多播器中; // 此时自定义的listener还没有进行实例化 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // 发布早期的监听事件集合 // 在refresh() 第一个方法 prepareRefresh() 中初始化了; // Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (!CollectionUtils.isEmpty(earlyEventsToProcess)) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } } }
3,发布事件 ==>重点是publishEvent方法进行了事件发布
该方法最终会调用:org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
/** * Finish the refresh of this context, invoking the LifecycleProcessor's * onRefresh() method and publishing the * {@link org.springframework.context.event.ContextRefreshedEvent}. */ protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. // 为上下文初始化生命周期处理器 initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. // 发布事件,新建ContextRefreshedEvent发布到监听器 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
/** * Publish the given event to all listeners. * <p>Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be application-specific or a * standard framework event) */ @Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); } /** * Publish the given event to all listeners. * <p>Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) */ @Override public void publishEvent(Object event) { publishEvent(event, null); } /** * Publish the given event to all listeners. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) * @param eventType the resolved event type, if known * @since 4.2 */ protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } } // Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
使用默认方法:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { @Nullable private Executor taskExecutor; @Nullable private ErrorHandler errorHandler; // 省略... @Override public void multicastEvent(ApplicationEvent event) { // resolveDefaultEventType会获取event 监听的类型,即该ApplicationEvent的泛型 multicastEvent(event, resolveDefaultEventType(event)); } @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); } } } /** * Invoke the given listener with the given event. * @param listener the ApplicationListener to invoke * @param event the current event to propagate * @since 4.1 */ protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { doInvokeListener(listener, event); } } @SuppressWarnings({"rawtypes", "unchecked"}) private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { // 调用监听器的响应方法 listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass())) { // Possibly a lambda-defined listener which we could not resolve the generic event type for // -> let's suppress the exception and just log a debug message. Log logger = LogFactory.getLog(getClass()); if (logger.isTraceEnabled()) { logger.trace("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } } }
调用链为:
--》publishEvent(new ContextRefreshedEvent(this));
--》getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
--》invokeListener(listener, event);
--》listener.onApplicationEvent(event);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能