spring 事件监听原理

  1. 首先看看在Spring如何实现自定义事件监听,首先定义事件:
public class MyEvent extends ApplicationEvent {

	public MyEvent(Object source) {
		super(source);
	}
}

  1. 然后定义一个事件监听器,注意监听器需要交给容器管理,所以需要标注@Component注解
@Component
public class MyListener implements ApplicationListener<ApplicationEvent> {

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if(event instanceof  MyEvent){
			System.out.println("事件开始了");
		}
	}
}

  1. 在具体的场景中发布一个事件, 注意这里发布事件需要通过ApplicatonContext发布,所以这里继承ApplicationContextAware, 这样在类实例化后会调用ApplicationContextAware的setApplicationContext()方法拿到ApplicationContext实例

    @Component
    public class Animal implements ApplicationContextAware{
        
        private ApplicationContext ac;
    
        public void speak(){
            //必须通过ApplicationContext发布事件
            ac.publishEvent(new MyEvent(ac));
        }
    
        @Override
        public void setApplicationContext(ApplicationContext arg0)
                throws BeansException {
              this.ac = arg0;       
        }
    }
    

到此处,自定义监听器已经完成,那么问题来,spring到底是怎么实现的,为什么在调用applicationContext的publishEvent()方法就能做到事件监听呢?下边采用问答的方式讲述实现原理

问题:applicationContext是怎么通过setApplicationContext()方法被设置到Animal对象中的呢?

对于这个问题,我们需要看Spring关于Bean的实例化过程,在Bean对象被实例化后,会调用各种后置处理器方法,找到Spring bean创建方法doCreateBean,我们会找到下边这样一段代码; populateBean()是属性填充,initializeBean()方法对bean做一些初始化工作,其实就是执行一些列的后置处理器方法, 然后我们在这个方法内部可以看到invokeAwareMethods(beanName, bean);方法调用,也正是通过这段代码实现applicationContext设置的

try {
			//属性添加,给实例对象填充属性
			populateBean(beanName, mbd, instanceWrapper);
			//初始化bean, 也就是生命周期回到,@PostConstruct,InitializingBean SmartInitializingSingleton,
			// 拿出所有的后置处理,进行调用
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		...
        
    //------------------------------------------------------------------
    //initializeBean方法的实现
    //------------------------------------------------------------------
   protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		} else {
			//这个地方调用接口Aware的方法,
			//例如当前bean实现了ApplicationContextAware接口,那么这个地方会调用这个接口的
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//执行bean后置处理,包括自定义的还有系统定义的0,
			// @PostCounstruct由系统提供的CommonAnnotationBeanPostProcessor进行处理
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//这里执行实现InitializingBean接口的方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//执行beanPostProcessor的applyBeanPostProcessorsAfterInitialization方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

	//----------------------------------------------------------------
	//如果当前类实现了Aware接口,或者该接口的字类,那么在这个地方会执行其对应的一些方法setBeanFactory()方法
    //------------------------------------------------------------------
	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

问题:通过applicationContext.publishEvent(new Event())发布事件后,监听器是如何监听到这个事件的?

在回答这个问题之前,我们先考虑一个问题,我们自定义了一个监听器类,而且在这个监听器类上添加了@Component注解,Spring是如何处理这个类的,会不会和普通bean的处理方式一样?

其实答案肯定是不一样,spring会判断这个bean是不是一个监听器,如果是监听器,会把这个bean放到applicationLisenters中。那么spring到底是如何处理的?

其实这个还是在bean实例化的时候处理器的,我们接着看initializeBean()方法,在这个方法类会执行一些列的后置处理器方法,我们发现在Spring中,提供了一个后置处理器为ApplicationListenerDetector,我们看看它提供了什么方法,我们看到,方法一开始就判断当前bean是不是一个ApplicationListener,最后把它添加到了applicaitonListentors中

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (bean instanceof ApplicationListener) {
			// potentially not detected as a listener by getBeanNamesForType retrieval
			Boolean flag = this.singletonNames.get(beanName);
			if (Boolean.TRUE.equals(flag)) {
				// singleton bean (top-level or inner): register on the fly
				this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
			}
			else if (Boolean.FALSE.equals(flag)) {
				if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
					// inner bean with other scope - can't reliably process events
					logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
							"but is not reachable for event multicasting by its containing ApplicationContext " +
							"because it does not have singleton scope. Only top-level listener beans are allowed " +
							"to be of non-singleton scope.");
				}
				this.singletonNames.remove(beanName);
			}
		}
		return bean;
	}

最后我们看看通过publishEvent()后又是怎么监听到这个事件的,getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);我们看到这个代码将事件传递给所有的监听器,在multicastEvent()方法中,会发现spring取出了所有的监听器,然后分别把事件传递给他们,然后调用invokeListener(listener, event);方法, 接着往里看, 最终发现调用了listener.onApplicationEvent(event)方法,发现了吧,我们自定义的监听就是重写了ApplicationListener的这个方法,所以最后事件就者被传递到我们自定的监听器了。

	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);
			}
		}
	}


	//------------------------------------------------------------------
	//事件处理
	//------------------------------------------------------------------
	@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;
			}
		}
	}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值