一. 引言
最近几天在深入学习了解下MQ相关的知识,做一个博客专栏。但最近在阅读RabbitMQ客户端代码的时候,遇到了很多Spring框架相关的陌生知识点,不断地去google,反倒是加深了对Spring相关的了解,比如今天在看到RabbitMQ的消息监听实现时,发现自己虽然在Spring源码解析时读过这一知识点,但在理解Rabbit消息监听实现时对事件的发布和监听还是没有头绪,所以在此好好学习记录下。
Spring构件的应用程序中,适当地使用事件发布与监听机制可以使我们的代码灵活度更高,降低耦合度。Spring提供了事件发布与监听的模型,在该模型中,事件发布方只需要将事件发布出去,无需关心有多少个对应的监听器;监听器无需关心是谁发布了事件,并且可以同时监听来自多个事件发布方的事件,通过这种机制,事件发布与监听是解耦的。
二.事件发布监听的案例
-
自定义事件
public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
source指事件发布源头,通常是ApplicationContext
-
事件发布
@Component @Slf4j public class MyEventPublisher implements ApplicationEventPublisherAware, ApplicationContextAware { private ApplicationContext applicationContext; private ApplicationEventPublisher applicationEventPublisher; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } public void publishMyEvent(){ log.info("发布事件开始"); MyEvent myEvent = new MyEvent(applicationContext); applicationEventPublisher.publishEvent(myEvent); log.info("发布事件结束"); } }
自定义事件发布器MyEventPublisher,事件发布时需要使用到ApplicationEventPublisher进行发布。通过实现ApplicationEventPublisherAware接口,调用回调setApplicationEventPublisher方法,为applicationEventPublisher赋值;同样在构造事件时需要传入Spring上下文,通过实现ApplicationContextAware接口,在回调setApplicationContext方法时对applicationContext进行赋值。
-
事件监听
-
注解监听
@Component @Slf4j public class MyAnnotationListener { @EventListener public void onMyEventPublished(MyEvent event){ log.info("收到自定义事件MyEvent--MyAnnotationListener"); } }
通过@EventListener注解标注的方法入参为MyEvent类型,所以只要MyEvent事件被发布了,该监听器就会起作用,即该方法被回调。
-
编程式监听
@Component @Slf4j public class MyEventlistener implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent event) { log.info("收到自定义事件MyEvent--MyEventlistener"); } }
通过实现ApplicationListener接口实现事件的监听,泛型的类型为监听的消息类型。
-
测试
@SpringBootApplication public class MyApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args); MyEventPublisher publisher = context.getBean(MyEventPublisher.class); publisher.publishEvent(); } }
-
三.事件发布监听过程
1. 事件发布监听原理
-
事件发布者发布事件
public void publishMyEvent(){ log.info("发布事件开始"); MyEvent myEvent = new MyEvent(applicationContext); applicationEventPublisher.publishEvent(myEvent); log.info("发布事件结束"); }
-
进入到AbstractpplicationContext类的publishEvent(ApplicationEvent event) 方法,进而调用publishEvent(Object event, @Nullable ResolvableType eventType)方法:主要是获取事件多播器,然后广播事件
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); Object applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent)event; } else { //判断event是否是ApplicationEvent类型,是的话使用PayloadApplicationEvent包装 applicationEvent = new PayloadApplicationEvent(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType(); } } if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { //获取事件多播器,然后广播事件 this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType); } if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext)this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
-
获取事件多播器方法:getApplicationEventMulticaster,直接返回abstractApplicationContext的applicationEventMulticaster属性
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException { if (this.applicationEventMulticaster == null) { throw new IllegalStateException("ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: " + this); } else { return this.applicationEventMulticaster; } }
-
调用SimpleApplicationEventMulticaster的multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType)方法进行事件广播
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Executor executor = this.getTaskExecutor(); Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } } } }
- 获取事件的所有监听者
- 若executor不为空,通过executor执行监听方法;否则直接调用监听方法
-
调用监听方法实际上调用了listener的onApplicationEvent方法
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { listener.onApplicationEvent(event); } catch (ClassCastException var6) { String msg = var6.getMessage(); if (msg != null && !this.matchesClassCastMessage(msg, event.getClass()) && (!(event instanceof PayloadApplicationEvent) || !this.matchesClassCastMessage(msg, ((PayloadApplicationEvent)event).getPayload().getClass()))) { throw var6; } Log loggerToUse = this.lazyLogger; if (loggerToUse == null) { loggerToUse = LogFactory.getLog(this.getClass()); this.lazyLogger = loggerToUse; } if (loggerToUse.isTraceEnabled()) { loggerToUse.trace("Non-matching event type for listener: " + listener, var6); } } }
2.多播器创建过程
可以看到多播器是从AbstractApplicationContext的applicationEventListener获取到的,接下来展开说明多播器是在何时创建的
-
通过在AbstractApplicationContext的applicationEventMulticaster属性上打断点,在程序启动时程序跳转到了AbstractApplicationContext的initApplicationEventMulticaster方法
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if (beanFactory.containsLocalBean("applicationEventMulticaster")) { this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class); if (this.logger.isTraceEnabled()) { this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { //===========此处赋值 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster); if (this.logger.isTraceEnabled()) { this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }
-
跟踪堆栈信息得到调用过程
-
SpringApplication.run()
-
…
-
run(String… args)
-
refreshContext(context)
-
…
-
AbstractApplicationContext.refresh()
-
initApplicationEventMulticaster()
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if (beanFactory.containsLocalBean("applicationEventMulticaster")) { this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class); if (this.logger.isTraceEnabled()) { this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { //=========此处赋值 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster); if (this.logger.isTraceEnabled()) { this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }
-
3. 监听器获取过程
a. 编程实现监听器注册过程
-
先查看获取监听器方法getApplicationListeners
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = source != null ? source.getClass() : null; AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType); AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null; AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey); if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever(); existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever); if (existingRetriever != null) { newRetriever = null; } } if (existingRetriever != null) { Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } } return this.retrieveApplicationListeners(eventType, sourceType, newRetriever); }
- 通过事件类型和事件源构件监听器缓存键
- 通过缓存键从缓存中获取监听器集合
- 集合为空时,新建一个监听追踪器,放到缓存中,调用retrieveApplicationListeners方法获取当前事件的监听器集合
-
retrieveApplicationListeners
- 从AbstractApplicationEventMulticaster的DefaultListenerRetriever属性获取所有事件的监听器和监听器Bean名称集合
- 遍历所有事件监听器,将符合当前事件的监听器集合添加到相应集合中
- 如果监听器Bean名称集合为空,遍历所有监听器集合,然后通过bean工厂从容器获取相应bean名称,并且类型为ApplicationListener的bean添加到集合中
- 将过滤后的事件监听器集合赋值给事件缓存追踪对象的相应属性,再次获取时从缓存中获取
-
最初是从AbstractApplicationEventMulticaster的DefaultListenerRetriever属性获取所有事件的监听器和监听器Bean名称集合,需要搞清楚这些属性是何时被赋值的
-
DefaultListenerRetriever.applicationListeners在addApplicationListener方法中被调用
public void addApplicationListener(ApplicationListener<?> listener) { synchronized (this.defaultRetriever) { // Explicitly remove target for a proxy, if registered already, // in order to avoid double invocations of the same listener. Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } }
-
往上追溯,在applicationContext的registerListeners方法中被调用
protected void registerListeners() { // Register statically specified listeners first. for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // 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); } } }
-
再追溯发现还是在SpringApplication.run方法中一步步调用的refresh方法
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException 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 { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); contextRefresh.end(); } } }
-
b 注解监听器注册过程
-
看@RabbitListener注解源码
/* @author Stephane Nicoll * @author Sam Brannen * @since 4.2 * @see EventListenerMethodProcessor * @see org.springframework.transaction.event.TransactionalEventListener */ @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EventListener { }
-
在EventListenerMethodProcessor中处理的注解监听,该类实现了SmartInitializingSingleton接口,回调afterSingletonsInstantiated方法
public void afterSingletonsInstantiated() { ConfigurableListableBeanFactory beanFactory = this.beanFactory; Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); String[] beanNames = beanFactory.getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class<?> type = null; try { type = AutoProxyUtils.determineTargetClass(beanFactory, beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } if (type != null) { if (ScopedObject.class.isAssignableFrom(type)) { try { Class<?> targetClass = AutoProxyUtils.determineTargetClass( beanFactory, ScopedProxyUtils.getTargetBeanName(beanName)); if (targetClass != null) { type = targetClass; } } catch (Throwable ex) { // An invalid scoped proxy arrangement - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex); } } } try { processBean(beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex); } } } } }
获取所有bean,然后进行遍历,调用processBean方法
private void processBean(final String beanName, final Class<?> targetType) { if (!this.nonAnnotatedClasses.contains(targetType) && AnnotationUtils.isCandidateClass(targetType, EventListener.class) && !isSpringContainerClass(targetType)) { Map<Method, EventListener> annotatedMethods = null; try { annotatedMethods = MethodIntrospector.selectMethods(targetType, (MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); } catch (Throwable ex) { // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex); } } if (CollectionUtils.isEmpty(annotatedMethods)) { this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) { logger.trace("No @EventListener annotations found on bean class: " + targetType.getName()); } } else { // Non-empty set of methods ConfigurableApplicationContext context = this.applicationContext; Assert.state(context != null, "No ApplicationContext set"); List<EventListenerFactory> factories = this.eventListenerFactories; Assert.state(factories != null, "EventListenerFactory List not initialized"); 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; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName + "': " + annotatedMethods); } } } }
- 获取被@EventListener注解的方法
- 如果找到了被@EventListener注解的方法,则通过事件监听工厂创建方法对应的ApplicationListener对象然后通过ApplicationListenerMethodAdapter适配,最终添加到上下文中。