Spring事件监听Listener

1、Spring事件原理

原理:观察者模式

spring的事件监听有三部分组成:
1)事件(ApplicationEvent)负责对应相应监听器 事件源发生某事件是特定事件监听器被触发的原因。

2)事件发布器(ApplicationEventMulticaster)对应于观察者模式中的被观察者/主题, 负责通知观察者(监听器) 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。

3)监听器(ApplicationListener)对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。

Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:
在这里插入图片描述

2、源码分析

1、applicationEventMulticaster提供了容器监听器的注册表
Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。
AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。
AbstractApplicationContext在refresh()这个容器启动方法中搭建了事件的基础设施,其中refresh()如下:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 1、准备刷新上下文环境,和主流程关系不大,主要是保存了容器的启动时间,启动标志等
			/** 一个早期事件监听器对象 */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/**
			 * 还是一些准备工作,添加了两个后置处理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
			 * 还设置了 忽略自动装配 和 允许自动装配 的接口,如果不存在某个bean的时候,spring就自动注册singleton bean
			 * 还设置了bean表达式解析器等
			 */
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.

				postProcessBeanFactory(beanFactory);

				/**
				 * 重点代码终于来了,可以说 这句代码是目前为止最重要,也是内容最多的代码了,我们有必要好好分析下
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 注册bean的后置处理器
				registerBeanPostProcessors(beanFactory);

				// 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.
				// 实例化我们剩余的单实例bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				/**最后容器刷新,发布刷新事件 (springcloud也是从这里启动的) */
				finishRefresh();
			}

			********

2、事件发布器的初始化
进入到refresh()方法-》initApplicationEventMulticaster()方法中

protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		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 {
			/** Spring自动使用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() + "]");
			}
		}
	}

Spring容器会先判断是否有配置的外部用户自定义的事件发布器(只要实现ApplicationEventMulticaster就可以了,Spring会通过反射的机制将其注册成容器的事件广播器),如果没有找到配置的外部事件广播器,Spring自动使用SimpleApplicationEventMulticaster作为事件广播器。

3、注册事件监听器

protected void registerListeners() {
		// Register statically specified listeners first.
		/** 获取容器中所有的监听器对象
		 * 这个时候正常流程是不会有监听器的,除非手动调用addApplicationListeners()
		 */
		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!
		/** 获取bean定义中的监听器对象,并且是实现了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...
		/** 在这里获取我们的早期事件 */
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		/** 在这里赋值null ,也就是至此之后都将没有早期事件了 */
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			/** 通过发布器的multicastEvent()方法进行播发早期事件 */
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。

4、发布事件
跟着finishRefresh();方法进入publishEvent(new ContextRefreshedEvent(this));方法如下:

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

在AbstractApplicationContext的publishEvent方法中,Spring委托**ApplicationEventMulticaster(事件发布器)**将事件通知给所有的事件监听器。

5、Spring默认的事件发布器SimpleApplicationEventMulticaster

/**
	 * 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 {
			/** 在这里调用监听器的onApplicationEvent()方法 */
			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;
			}
		}
	}

默认的事件发布器,会遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法。
由于SimpleApplicationEventMulticaster的taskExecutor的实现类是SyncTaskExecutor,因此,事件监听器对事件的处理,是同步进行的
从代码可以看出,applicationContext.publishEvent()方法,需要同步等待各个监听器处理完之后,才返回。

也就是说,Spring提供的事件机制,默认是同步的。如果想用异步的,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean。

Spring发布事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。

Sping事件体系所使用的设计模式是:观察者模式。ApplicationListener是观察者接口,接口中定义了。onApplicationEvent方法,该方法的作用是对ApplicationEvent事件进行处理。

3、代码实现

1)Order类

public class Order {
    private Integer id;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

2)自定义事件

/**
 * 自定义事件,实现ApplicationEvent接口
 */
public class OrderEvent  extends ApplicationEvent implements Serializable {

	private static final long serialVersionUID = 1L;

    private String name;

    public OrderEvent(Object source, String name) {
        super(source);
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

3)事件监听器 - 基于接口实现
该方法的作用是对ApplicationEvent事件进行处理。

@Component
//@Lazy
public class OrderEventListener implements ApplicationListener<OrderEvent> {//}   {

    // 基于注解的
//    @EventListener(OrderEvent.class)
	@Override
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("orderListener")){
            System.out.println("Order processing.......");
        }
    }

}

4)测试类

public class MainStat1 {

	public static void main(String[] args) throws Exception {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		Order order = new Order();
		order.setId(1);
		System.out.println("order.....");
		applicationContext.publishEvent(new OrderEvent(order,"orderListener"));
		System.out.println("print log...");
	}

}

测试截图:
在这里插入图片描述
打印了事件监听器中的Order processing…,说明OrderEvent事件被监听到了,触发了事件监听器处理下订单逻辑处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值