当前位置:   article > 正文

【Spring源码】事件监听机制全解_java spring mvc 监听接口返回内容

java spring mvc 监听接口返回内容

Spring事件驱动机制

更多学习笔记在这:huangxuan828的gitee学习笔记

设计模式

观察者模式

传统观察者模式由:观察者和主题两个角色组成。观察者对主题的监听关系在主题中维护,耦合度较重。

Spring事件驱动机制在JDK原生的事件监听体系上扩展,并对观察者模式做了改进,将其划分为3大角色,完全解耦(把原有主题中负责维护主题与观察者映射关系以及在自身状态改变时通知观察者的职责从中抽出,放入到事件组播器中)

  • 事件(主题)
  • 事件监听器(观察者)
  • 事件组播器(观察者对主题的监听关系 & 事件状态变更时触发通知)

适配器模式

@EventLister 标记的方法被适配成 ApplicationListenerMethodAdapter 类,从而能够注册到组播器中

策略模式

EventListenerFactory 事件监听器工厂是抽象的策略类

DefaultEventListenerFactoryTransactionalEventListenerFactory 是具体的策略、

通过 factory.supportsMethod(method) 选择出适合当前Method的策略类

Spring事件监听机制

三大角色

  • 事件:ApplicationEvent(抽象类,继承自JDK原生的EventObject,该类中的 Object source 即为事件源)

  • 事件监听器:ApplicationListener(接口,继承自JDK原生的EventListener,该接口啥也没有,所有监听器都应实现该接口)

  • 事件组播器:ApplicationEventMulticaster(接口,事件组播器的基本接口,定义了组播器的基本功能)

    该事件组播器被组装在ApplicationContext平台上,ApplicationContext通过ApplicationEventMulticaster进行事件的发布

    ApplicationContext接口,继承自ApplicationEventPublisher,因此 具备发布事件的能力: publishEvent()

    即:我们可以通过ApplicationContext的 publishEvent()去调用 ApplicationEventMulticaster 来发布事件

源码实现

源码应从 AbstractApplicationContext 类在刷新容器方法 refresh() 中的 三大步骤 展开

初始化事件组播器

AbstractApplicationContext#initApplicationEventMulticaster()

如果容器内没有,默认使用 SimpleApplicationEventMulticaster 作为事件组播器

protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    /** 如果容器有id=applicationEventMulticaster的Bean,则使用该Bean作为事件组播器
     *  用户可以使用自定义的id为applicationEventMulticaster的事件组播器(继承AbstractApplicationEventMulticaster)
     */
		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 {
			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() + "]");
			}
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
注册监听器
注册监听器(impl ApplicationListener)

AbstractApplicationContext#registerListeners()

把容器中 实现了 ApplicationListener 的监听器 的BeanName 注册事件组播器 的监听器列表中(组播器被组装在容器中)

protected void registerListeners() {
		// 注册 已在容器中的(this.applicationListeners里的) 且已被初始化的ApplicationListener
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

    	// 注册 所有ApplicationListener
        // (getBeanNamesForType()是从BeanFactory的beanDefinitionNames中取的,包括了未初始化的ApplicationListener)
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// 监听器注册后, 立即处理 早期的 容器启动过程内部所产生的事件
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
适配@EventLister标注的方法为监听器并注册

AbstractApplicationContext#finishBeanFactoryInitialization(beanFactory)

完成容器剩余的所有初始化工作(BeanFactory的初始化 & 单例Bean的初始化)

DefaultListableBeanFactory#preInstantiateSingletons()

初始化所有非懒加载的单例Bean

@Override
public void preInstantiateSingletons() throws BeansException {
   /** EventListenerMethodProcessor 实现了 SmartInitializingSingleton 接口
    *  因此, 这里会接着执行 EventListenerMethodProcessor#afterSingletonsInstantiated()方法
    */ 
    smartSingleton.afterSingletonsInstantiated();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

EventListenerMethodProcessor#afterSingletonsInstantiated()

@Override
public void afterSingletonsInstantiated() {
    processBean(beanName, type);
}
  • 1
  • 2
  • 3
  • 4

EventListenerMethodProcessor#processBean(final String beanName, final Class<?> targetType)

private void processBean(final String beanName, final Class<?> targetType) {
    // 遍历所有被@EventListener标注的方法
    for (Method method : annotatedMethods.keySet()) {
        // 拿到每个EventListenerFactory, 这里是策略模式
        // @EventListener对应DefaultEventListenerFactory
        // @TransactionalEventListener对应TransactionalEventListenerFactory
        for (EventListenerFactory factory : factories) {
            // supportsMethod表示是否支持去处理此方法(因为我们可以定义处理器,只处理指定的Method)  
            if (factory.supportsMethod(method)) {
                // 把这个方法转为一个可以执行的方法(主要和访问权限有关)
                Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                // 使用对应的事件工厂,把这个方法适配成一个监听器(ApplicationListenerMethodAdapter类型)
                ApplicationListener<?> applicationListener =
                    factory.createApplicationListener(beanName, targetType, methodToUse);
                // 显然为true, 初始化这个事件监听器:ApplicationListenerMethodAdapter
                if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                    ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                }
                // 注册监听器到组播器中
                context.addApplicationListener(applicationListener);
                break;
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
事件发布

事件发布流程图:

在这里插入图片描述

AbstractApplicationContext#publishEvent

public void publishEvent(ApplicationEvent event) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}
		getApplicationEventMulticaster().multicastEvent(event);
		// 判断当前ApplicationContext有没有父级容器 ,如果有则执行父级的publishEvent
    	// 所以在这里:ApplicationEvent可能会被被多次执行了
		if (this.parent != null) {
			this.parent.publishEvent(event);
		}
	}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

事件组播器负责发布事件:SimpleApplicationEventMulticaster#multicastEvent(applicationEvent, eventType)

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    // 若set了执行器,那所有的监听器都将会异步执行
    @Nullable
    private Executor taskExecutor;
    // 监听者执行失败的回调(比如做回滚等等)
    @Nullable
    private ErrorHandler errorHandler;    
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));    
    	 // 遍历所有的事件监听器,并根据事件类型和事件源类型匹配出合适的监听器
    	for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            // Spring默认情况下同步执行这些监听器的,我们可以调用set方法配置一个执行器(建议)
    		Executor executor = getTaskExecutor();
    		// 异步执行
    		if (executor != null) {
    			executor.execute(() -> invokeListener(listener, event));
    		} else { // 同步执行
    			invokeListener(listener, event);
    		}
    	}
    }
	// invokeListener内的doInvokeListener()方法
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            // 如果是实现了ApplicationListener接口的事件,则直接调用其中的onApplicationEvent()方法;
            //如果是用@EventListener标注的事件,则调用ApplicationListenerMethodAdapter中的onApplicationEvent()方法
            listener.onApplicationEvent(event);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

事件监听器调用 ApplicationListener#onApplicationEvent() 来处理事件

@EventListener标注的监听器 ApplicationListenerMethodAdapter#onApplicationEvent()#processEvent(event)

public void processEvent(ApplicationEvent event) {
    Object[] args = resolveArguments(event);
    // 解析condition表达式(注意,此处把args传进去了,因此我们的表达式里是可以用这个参数的)
    if (shouldHandle(event, args)) {
        // 执行ApplicationListenerMethodAdapter中保存的被@EventListener标注的Method
        // 事件的传递性:如果有返回值,则把返回值继续当成一个事件发布
        Object result = doInvoke(args);
        if (result != null) {
            handleResult(result);
        }
        else {
            logger.trace("No result object given - no result to handle");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

补充

ApplicationListener和@EventListener的区别

ApplicationListener和@EventListener 最终都会被注册到 Spring 容器内的 事件组播器里

但是:@EventListener存在漏事件的问题,而ApplicationListener能监听到所有的相关事件

  • 通过实现ApplicationListener接口自定义的监听器:

该监听器会监听到所有时段发布的事件

refresh()的prepareBeanFactory(beanFactory) 阶段,容器会注册一个名为:事件监听器探测器的BeanPostProcessor

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
}
  • 1
  • 2
  • 3

该探测器实现了 BeanPostProcessor 接口。从而,可以在整个容器层面,对所有Bean的生命周期进行 后置增强

在这里插入图片描述

该探测器类的后置增强源码如下:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    // 判断该bean是否实现了ApplicationListener接口
    if (this.applicationContext != null && bean instanceof ApplicationListener) {
        Boolean flag = this.singletonNames.get(beanName);
        if (Boolean.TRUE.equals(flag)) {
            // 将实现了ApplicationListener接口的BeanName注册到事件组播器applicationEventMulticaster中
            this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
        }
        // ...
    }
    return bean;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 采用@EventListener方法定义的监听器:

由于它的注册时间非常晚(finishBeanFactoryInitialization(beanFactory) ),是在所有的bean实例化、初始化完毕之后才会注册。

所以在此前发布的事件将无法被监听到,比如:容器的earlyApplicationEvents属性中发布的事件;或@PostConstruct方法中发布的事件;在普通的单例Bean初始化期间(比如给属性赋值时、构造函数内)发布的事件

注解方式监听器注册失败

  • 使用 @EventListener和@TransactionalEventListener 标注的监听器方法,其访问权限不得低于 protected

  • @EventListener和@TransactionalEventListener 无法标注在某个接口的实现类当中

    原因:Spring在解析标注有此注解的方法的时候是通过JDK动态代理来实现的

    public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
        ...
        private void processBean(final String beanName, final Class<?> targetType) {
        	...  // jdk 动态代理
        		Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
        	...
        }
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

桥接方法是什么

EventListenerMethodProcessor#processBean(beanName, type)

在使用事件工厂创建出Method的适配器类 ApplicationListenerMethodAdapter时:

ApplicationListenerMethodAdapter 在构造方法中,对 Method 入参进行了桥接判断

public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
    this.beanName = beanName;
    // 如果入参Method是桥接方法,则寻找出它的原方法
    this.method = BridgeMethodResolver.findBridgedMethod(method);
    this.targetMethod = (!Proxy.isProxyClass(targetClass) ?
                         AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
    this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);

    EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
    this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
    this.condition = (ann != null ? ann.condition() : null);
    this.order = resolveOrder(this.targetMethod);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

具体什么是桥接方法,参照:https://blog.csdn.net/a296007576/article/details/113041927

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/799286
推荐阅读
相关标签
  

闽ICP备14008679号