Spring的扩展点3:监听器机制

1 自定义ApplicationEventListener

自定义ApplicationEventListener的两种方式:

  • 实现ApplicationListener接口
  • 使用@EventListener注解
package com.woods.listener;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.woods.listener")
public class App {
}

package com.woods.listener;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext configApplicationContext =
				new AnnotationConfigApplicationContext(App.class);

		// 发布一个自定义事件
		configApplicationContext.publishEvent(new ApplicationEvent(new String("This is a custom listener")) {
			@Override
			public String toString() {
				return super.toString();
			}
		});
		configApplicationContext.close();
	}
}

package com.woods.listener;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 通过实现ApplicationListener接口创建自定义的ApplicationEventListener
 */
@Component
public class MyApplicationEventListener implements ApplicationListener<ApplicationEvent> {
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		System.out.println("onApplicationEvent收到事件 " + event);
	}

	/**
	 * 如果@EventListener标记的方法的返回值不是void,返回的对象将被包装成一个PayloadApplicationEvent再次被发送。
	 * */
	//	@EventListener
	//	public int doSomething1(ApplicationEvent event) {
	//		System.out.println("EventListener1收到事件 " + event);
	//		return 1;
	//	}
}

package com.woods.listener;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * 通过@EventListener注解创建自定义的ApplicationEventListener
 */
@Component
public class MyApplicationEventListener2 {
	@EventListener
	public void doSomething2(ApplicationEvent event) {
		System.out.println("EventListener收到事件 " + event);
	}
}

上面代码的运行结果为:

EventListener收到事件 org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@d716361, started on Tue Jul 28 20:26:01 CST 2020]
onApplicationEvent收到事件 org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@d716361, started on Tue Jul 28 20:26:01 CST 2020]
EventListener收到事件 com.woods.listener.Main$1[source=This is a custom listener]
onApplicationEvent收到事件 com.woods.listener.Main$1[source=This is a custom listener]
EventListener收到事件 org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@d716361, started on Tue Jul 28 20:26:01 CST 2020]
onApplicationEvent收到事件 org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@d716361, started on Tue Jul 28 20:26:01 CST 2020]

Spring的ApplicationContext的事件处理机制是对Observer设计模式的一种实现。

SpringFramework官方文档的1.15.2节对SpringFramework的事件机制进行了讲解,主要涉及到的对象包括

  • ApplicationEvent,代表事件。Spring提供的标准事件包括ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent、ServletRequestHandledEvent。用户可以通过继承ApplicationEvent自定义事件。
  • ApplicationListener,代表事件监听器。可以通过实现ApplicationListener接口或通过@EventListener注解(Spring4.2开始支持)标注方法的方式创建自定义的事件监听器。ApplicationListener#onApplicationEvent用于处理接收到的事件,默认情况下在调用者线程中处理。如果在@EventListener注解上加上@Async,则会在一个单独的线程中进行事件的处理。此外,还可以在@EventListener注解上加上@Order注解确定ApplicationListener的处理顺序。
  • ApplicationEventPublisher,事件发布器。ApplicationEventPublisher#publishEvent方法可以发布事件。可以通过实现ApplicationEventPublisherAware接口获得ApplicationEventPublisher。
  • ApplicationEventMulticaster,事件广播器。ApplicationEventMulticaster用来管理ApplicationListener,例如addApplicationListener、removeApplicationListener。此外,可以向listener广播事件,即ApplicationEventMulticaster#multicastEvent(ApplicationEvent)

2 源码分析

2.1 对ApplicationListener子类和@EventListener的处理流程

  • 1 在AnnotationConfigApplicationContext的构造方法中,向BeanFactory注册了两个BeanDefinition,分别是EventListenerMethodProcessorDefaultEventListenerFactory
    EventListenerMethodProcessor实现了BeanFactoryPostProcessor接口和SmartInitializingSingleton接口,EventListenerMethodProcessor的postProcessAfterInitialization方法会将实现了ApplicationListener接口的类添加到ApplicationEventMulticaster,而EventListenerMethodProcessor的afterSingletonsInstantiated方法则会让DefaultEventListenerFactory为标注了@EventListener注解的方法生成ApplicationListenerMethodAdapter,然后添加到ApplicationEventMulticaster。
    DefaultEventListenerFactory是为@EventListener标注的方法生成ApplicationListener的工厂。

  • 2 在AbstractApplicationContext的refresh方法中,首先执行prepareBeanFactory方法,该方法向BeanFactory添加了ApplicationListenerDetector这个Bean。ApplicationListenerDetector实现了BeanPostProcessor接口,在Bean实例化之后会调用BeanPostProcessor的postProcessAfterInitialization方法。ApplicationListenerDetector的postProcessAfterInitialization会把实现了ApplicationListener接口的Bean,也就是用户自定义的ApplicationListener注册到ApplicationEventMulticaster上。

  • 3 接着执行refresh中的invokeBeanFactoryPostProcessor方法。由于在第1步中注册的EventListenerMethodProcessor实现了BeanFactoryPostProcessor接口,因此在这里会创建EventListenerMethodProcessor对应的Bean,并调用EventListenerMethodProcessor的postProcessBeanFactory方法,该方法会根据第1步中添加到BeanFactory中的EventListenerMethodProcessor对应的BeanDefinition,创建出EventListenerMethodProcessor对应的Bean。在EventListenerMethodProcessor的afterSingletonsInstantiated方法中,会先获取所有的DefaultEventListenerFactory,EventListenerMethodProcessor会为标注了@EventListener的方法生成ApplicationListenerMethodAdapter,然后EventListenerMethodProcessor会把生成的ApplicationListenerMethodAdapter并绑定到ApplicationEventMulticaster上。
    经过上面3步,EventListenerMethodProcessor、DefaultEventListenerFactory和ApplicationListenerDetector都已经是Bean了。

  • 4 initApplicationEventMulticaster方法中创建了ApplicationEventMulticaster的实现类,即SimpleApplicationEventMulticaster,所有的ApplicationListener都会注册到SimpleApplicationEventMulticaster中。在SimpleApplicationEventMulticaster发布事件时,会把事件传递给每个ApplicationListener,每个ApplicationListener调用onApplicationEvent方法处理收到的事件。

  • 5 registerListeners方法将所有ApplicationListener对应的BeanName关联到了ApplicationEventMulticaster上。

  • 6 finishBeanFactoryInitialization方法完成单实例Bean的创建。创建完成后,会执行到BeanPostProcessor的postProcessAfterInitialization方法。ApplicationListenerDetector实现了BeanPostProcessor接口,它的postProcessAfterInitialization会把实现了ApplicationListener接口的Bean,也就是用户自定义的ApplicationListener注册到ApplicationEventMulticaster上。

  • 7 在finishBeanFactoryInitialization方法方法的最后,会执行smartSingleton.afterSingletonsInstantiated()方法。ApplicationListenerDetector实现了SmartInitializingSingleton接口,在EventListenerMethodProcessor的afterSingletonsInstantiated方法中,会先获取所有的DefaultEventListenerFactory,EventListenerMethodProcessor会为标注了@EventListener的方法生成ApplicationListenerMethodAdapter,然后EventListenerMethodProcessor会把生成的ApplicationListenerMethodAdapter并绑定到ApplicationEventMulticaster上。
    至此,实现了ApplicationListener接口的以及标注了@EventListener注解的方法都变成了ApplicationListener并关联到了ApplicationEventMulticaster中。

在这里插入图片描述

2.2 几个重要的类

  • ApplicationListenerDetector处理实现了ApplicationListener接口的类。具体来讲,ApplicationListenerDetector实现了BeanPostProcessor接口,
    在ApplicationListener子类被创建成Bean之后,ApplicationListenerDetector的postProcessAfterInitialization方法会将ApplicationListener子类添加到applicationEventMulticaster中,这样就把用户自定义的ApplicationListener和ApplicationEventMulticaster联系在了一起。

  • EventListenerMethodProcessorDefaultEventListenerFactory处理@EventListener标注的方法,为这样的方法生成ApplicationListenerMethodAdapter(ApplicationListenerMethodAdapter实现了ApplicationListener接口)并添加到applicationEventMulticaster中,这样就把@EventListener标注的方法生成的ApplicationListener和ApplicationEventMulticaster联系在了一起。

2.3 源码分析

与事件处理相关的代码分散在AnnotationConfigApplicationContext初始化过程的各个阶段,主要包括:

  • AnnotationConfigApplicationContext构造方法,this.reader = new AnnotatedBeanDefinitionReader(this)。
    这里向BeanFactory中添加EventListenerMethodProcessor和DefaultEventListenerFactory这两个BeanDefinition。EventListenerMethodProcessor和DefaultEventListenerFactory与事件处理相关。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		
		......省略部分无关代码

		// EventListenerMethodProcessor是BeanFactoryPostProcessor
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}
		// DefaultEventListenerFactory,为@EventListener标注的方法生成ApplicationListenerMethodAdapter
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}

EventListenerMethodProcessor的postProcessBeanFactory方法如下。该方法将DefaultEventListenerFactory生成Bean,存储到eventListenerFactories中。

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.beanFactory = beanFactory;

		Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
		List<EventListenerFactory> factories = new ArrayList<>(beans.values());
		AnnotationAwareOrderComparator.sort(factories);
		this.eventListenerFactories = factories;
	}

EventListenerMethodProcessor的afterSingletonsInstantiated方法如下。该方法的主要逻辑是调用上面postProcessBeanFactory产生的eventListenerFactories中的每个EventListenerFactory的createApplicationListener方法,为标注了@EventListener注解的方法生成ApplicationListenerMethodAdapter,然后将该ApplicationListener与ApplicationEventMulticaster关联起来。

@Override
	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) {
			......省略部分代码
					try {
						processBean(beanName, type);
					}
					catch (Throwable ex) {
						throw new BeanInitializationException("Failed to process @EventListener " +
								"annotation on bean with name '" + beanName + "'", ex);
					}
				}
			}
		}
	}


private void processBean(final String beanName, final Class<?> targetType) {
		......
		// 取出postProcessBeanFactory生成的DefaultEventListenerFactory Bean实例
				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));
							// 调用DefaultEventListenerFactory的createApplicationListener方法,为标注了@EventListener注解的方法生成ApplicationListenerMethodAdapter
							ApplicationListener<?> applicationListener =
									factory.createApplicationListener(beanName, targetType, methodToUse);
							if (applicationListener instanceof ApplicationListenerMethodAdapter) {
								((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
							}
							// 添加到ApplicationContext中并添加到ApplicationEventMulticaster中
							context.addApplicationListener(applicationListener);
							break;
						}
					}
				}
		.......
	}
  • AbstractApplicationContext的refresh方法。

    • initApplicationEventMulticaster。默认创建一个SimpleApplicationEventMulticaster。
    • registerListeners()。获取ApplicationListener的BeanName,添加到SimpleApplicationEventMulticaster中。
    • finishBeanFactoryInitialization(beanFactory)。创建MyApplicationEventListener2这个Bean时,在initializeBean方法中,会调用ApplicationListenerDetector的postProcessAfterInitialization方法,将MyApplicationEventListener2这个Bean关联到SimpleApplicationEventMulticaster上。

对实现了ApplicationListener接口的处理,这里是上面例子中的MyApplicationEventListener2
在这里插入图片描述

对标注了@EventListener注解的方法的处理,这里是MyApplicationEventListener2的doSomething2方法。
在这里插入图片描述

2.4 事件的发送与接收

终于到了发送事件这个轻松愉快的环节,我们看下ContextRefreshedEvent事件是怎么发送以及如何被我们自定义的ApplicationListener处理的。


	// 1 Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// 2 获取ApplicationEventMulticaster,调用multicastEvent方法		
	getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

	// 3 拿到所有的ApplicationListener,调用每个的onApplicationEvent方法处理事件
	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);
			}
		}
	}

调用栈如下
在这里插入图片描述

SpringFramework系列目录

SpringFramework系列目录

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值