Spring中事件驱动开发,ApplicationListener及ApplicationEventMulticaster

目录

一、Spring中事件驱动开发,事件监听机制

二、ApplicationEventMulticaster事件多播器

三、ApplicationListener监听器注册流程

四、创建Listener的方式

1. 编程实现ApplicationListener接口

2. 使用@EventListener注解 

五、事件发布流程


一、Spring中事件驱动开发,事件监听机制

Spring中是通过ApplicationListener及ApplicationEventMulticaster来进行事件驱动开发的,即实现观察者设计模式或发布-订阅模式;

事件(ApplicationEvent) :负责对应相应监听器,事件源发生某事件是特定事件监听器被触发的原因;

监听器(ApplicationListener) :监听容器中发布的事件,只要事件发生,就会触发监听器的回调,来完成事件驱动开发,属于观察者设计模式中的Observer(观察者)对象;

事件发布器(ApplicationEventMulticaster) :事件发布器可以认为是事件监听的容器,对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器,即通知所有的观察者对象,属于观察者设计模式中的Subject(主题)对象;

二、ApplicationEventMulticaster事件多播器

1. ApplicationEventMulticaster的初始化

事件多播器是在Spring容器启动过程中(refresh()方法中)初始化的,初始化步骤:

① 先去容器中找有没有beanName为"applicationEventMulticaster"的BeanDefination,如果有就使用这一个;

② 如果没有就创建一个,并添加到容器中,默认为SimpleApplicationEventMulticaster;

// Initialize event multicaster for this context.
// 初始化事件多播器,设置ApplicationContext的applicationEventMulticaster,可以是用户设置的,或者是默认的SimpleApplicationEventMulticaster
initApplicationEventMulticaster();

protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   /**
    * 判断容器中是否存在beanName为applicationEventMulticaster的BeanDefination
	* 自定义的事件多路广播器,必须实现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
		 */
		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. SimpleApplicationEventMulticaster类图

AbstractApplicationEventMulticaster的内部类DefaultListenerRetriever中维护了一个Set,

private class DefaultListenerRetriever {

	public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

	public final Set<String> applicationListenerBeans = new LinkedHashSet<>();

	public Collection<ApplicationListener<?>> getApplicationListeners() {
		List<ApplicationListener<?>> allListeners = new ArrayList<>(
					this.applicationListeners.size() + this.applicationListenerBeans.size());
		allListeners.addAll(this.applicationListeners);
		if (!this.applicationListenerBeans.isEmpty()) {
			BeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : this.applicationListenerBeans) {
				try {
					ApplicationListener<?> listener =
							beanFactory.getBean(listenerBeanName, ApplicationListener.class);
					if (!allListeners.contains(listener)) {
						allListeners.add(listener);
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Singleton listener instance (without backing bean definition) disappeared -
					// probably in the middle of the destruction phase
				}
			}
		}
		AnnotationAwareOrderComparator.sort(allListeners);
		return allListeners;
	}
}

三、ApplicationListener监听器注册流程

1.  ApplicationListener的注册

注册事件监听器是在事件发布器初始化之后进行的,因为注册事件监听器,其实最终就是将事件监听器添加到事件发布器中,所以事件发布器要先于事件监听器初始化,事件监听器注册步骤如下:

protected void registerListeners() {
	// Register statically specified listeners first.
	//getApplicationListeners()获取的是通过context.addApplicationListener(new MyApplicationListener())添加的ApplicationListener
	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!
	//获取beanFactory中所有ApplicationListener类型的listenerBeanName,到此时Spring实例化bean的步骤还没有执行,所以将listenerBeanName添加到事件发布器中
	//这里获得的listenerBeanNames不包括上面getApplicationListeners()方法获得的ApplicationListener
	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...
	// 添加了事件监听器后,判断是否有earlyApplicationEvents,如果有就使用事件广播器发布earlyApplicationEvents
	// earlyApplicationEvents表示在事件广播器还没生成好之前ApplicationContext所发布的事件
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}

四、创建Listener的方式

创建Listener的方式有两种:

方式1:编程实现ApplicationListener接口

方式2:使用@EventListener注解

1. 编程实现ApplicationListener接口

1.1. 实现 public interface ApplicationListener<E extends ApplicationEvent> 接口,监听 ApplicationEvent 及其下面的子事件:

/**
 * 事件监听器一般是由开发者自己定义
 * 定义事件监听器
 */
@Component
//@Lazy
public class MyApplicationListener implements ApplicationListener{

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		event = (PayloadApplicationEvent)event;
		System.out.println(((PayloadApplicationEvent<?>) event).getPayload());
	}
}

1.2. 关于ApplicationListenerDetector

Spring是怎么识别我们自定义的bean是不是监听器呢?就是通过ApplicationListenerDetector,

ApplicationListenerDetector是一个BeanPostProcessor,在初始化后会执行postProcessAfterInitialization()方法,如果当前bean是ApplicationListener类型,将其添加到applicationContext的applicationListeners中(注意:这里并不是直接添加到事件发布器中);

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    /**
	 * 会先判断bean是否是ApplicationListener类型
	 * 如果是通过@EventListener来声明的事件监听器,那不会进入到这个if
	 * 只有通过实现ApplicationListener接口这种方式的事件监听器会进入到if执行
	 */
	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;
}
/** Statically specified listeners. */
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

2. 使用@EventListener注解 

2.1. 通过EventListenerMethodProcessor处理器来解析@EventListener注解

@EventListener注解使用示例:

@Component
public class UserService {

	/**
	 * 定义事件监听器
	 */
	@EventListener
	public void eventMethod(ApplicationEvent event){
		System.out.println(event);
	}

}

原理:EventListenerMethodProcessor实现了SmartInitializingSingleton接口的afterSingletonsInstantiated()方法,在该方法中会筛选出每个bean中所有加了@EventListener注解的方法,并通过EventListenerFactory将其注册为一个ApplicationListener的instance,解析如下:

private void processBean(final String beanName, final Class<?> targetType) {
	if (!this.nonAnnotatedClasses.contains(targetType) &&
		 AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
				!isSpringContainerClass(targetType)) {

		// 找到所有加了@EventListener注解的方法
		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) {
					// 利用EventListenerFactory来对加了@EventListener注解的方法生成ApplicationListener对象
					if (factory.supportsMethod(method)) {
						Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
						//加了@EventListener注解的方法对应的是什么样的ApplicationListener,取决于factory是怎么创建的,默认使用的是DefaultEventListenerFactory
						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);
			}
		}
	}
}

说明:这里的EventListenerFactory默认使用的是DefaultEventListenerFactory,作用是将加了@EventListener注解的方法封装成为ApplicationListener对象;

2.2. EventListenerMethodProcessor的类图

2.3. 关于SmartInitializingSingleton

public interface SmartInitializingSingleton {

	/**
	 * Invoked right at the end of the singleton pre-instantiation phase,
	 * with a guarantee that all regular singleton beans have been created
	 * already. {@link ListableBeanFactory#getBeansOfType} calls within
	 * this method won't trigger accidental side effects during bootstrap.
	 * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
	 * lazily initialized on demand after {@link BeanFactory} bootstrap,
	 * and not for any other bean scope either. Carefully use it for beans
	 * with the intended bootstrap semantics only.
	 */
	void afterSingletonsInstantiated();

}
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		// 获取合并后的BeanDefinition
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName );
		//BeanDefinition如果是抽象的,是不会创建bean的(抽象的BeanDefinition和抽象的类是不一样的,抽象类在扫描的时候就会有判断,不会生成BeanDefinition)
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				// 获取FactoryBean对象
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);//创建FactoryBean对象
				if (bean instanceof FactoryBean) {
					FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(
								(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						// 创建真正的Bean对象(getObject()返回的对象)
						getBean(beanName);
					}
				}
			}
			else {
				// 创建Bean对象
				getBean(beanName);
			}
		}
	}

	// 所有的非懒加载单例Bean都创建完了后
	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
					.tag("beanName", beanName);
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
			smartInitialize.end();
		}
	}
}

说明:当所有非懒加载的单例bean都创建完之后,就会执行SmartInitializingSingleton的afterSingletonsInstantiated()方法,而EventListenerMethodProcessor就实现了SmartInitializingSingleton接口;

流程图

五、事件发布流程

以发布ContextRefreshedEvent事件为例:

1. publishEvent(new ContextRefreshedEvent(this)),发布事件;

2. 获取事件多播器并广播事件,既然是广播,如果定义了多个事件监听器,那么当发布一个事件的时候,这些事件监听器都会收到这个事件;

getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

3. 获取到所有的ApplicationListener;

/**
 * 广播事件
 * 如果定义了多个事件监听器,当发布一个事件的时候,这些事件监听器都会收到这个事件
 */
@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);
		}
	}
}

如果有Executor,可以支持使用Executor进行异步派发,否则,以同步的方式直接执行listener方法,invokeListener(listener, event),都是拿到listener回调onApplicationEvent()方法;、

流程图

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值