Spring事件的组件
主要是3个组件:
1.ApplicationEvent 事件
2.ApplicationListener 监听器,对事件进行监听
3.ApplicationEventMulticaster 事件广播器,将publish的事件广播给所有的监听器。
事件
ContextRefreshedEvent :当ApplicationContext初始化或者刷新,将会发布,例如使用ConfigurableApplicationContext接口调用refresh方法,初始化意味着加载所有的bean,同时
ApplicationContext是支持热刷新。
ContextStartedEvent:当ApplicationContext启动的时候,将会调用start方法,发布此事件。
ContextStoppedEvent:当容器停止的时候,发布事件。
ContextClosedEvent:当容器关闭的时候,发布事件。
RequestHandledEvent:http请求完成后,发布事件。
监听器
ApplicationListener:ApplicationContext容器内部自定义事件监听器接口,继承自java.util.EventListener,ApplicationContext容器在启动时,会自动识别并加载EventListener类型bean的定义,一旦容器事件发布,将会通知注册到容器的监听器。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
发布事件者
ApplicationEventPublisher和ApplicationEventMulticaster
ApplicationEventPublisher:是一个封装事件发布接口,作为ApplicationContext父类接口。
ApplicationEventMulticaster:管理ApplicationListener对象,并且发布它们。
ApplicationContext继承ApplicationEventPublisher而担当者事件发布的角色,而ApplicationContext并没有进行事件的发布,而是交给了AbstractApplicationEventMulticaster来实现事件监听器的管理。
简单实例
模拟人民银行利息调整,通知到其他银行的事件。
利息事件
package org.lzyer.test; import org.springframework.context.ApplicationEvent; /** * Created by Administrator on 2017/10/23. */ public class ExRateChangeEvent extends ApplicationEvent { /** * Create a new ApplicationEvent. * * @param source the component that published the event (never {@code null}) */ public ExRateChangeEvent(Object source) { super(source); } }
农业银行监听器
package org.lzyer.test; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * Created by Administrator on 2017/10/23. */ @Component public class ABCListener implements ApplicationListener<ApplicationEvent> { @Override public void onApplicationEvent(ApplicationEvent event) { if(event instanceof ExRateChangeEvent){ System.out.println("农业银行收到->"+event.getSource()); } } }
工商银行监听器
package org.lzyer.test; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * Created by Administrator on 2017/10/23. */ @Component public class ICBCListener implements ApplicationListener<ApplicationEvent> { @Override public void onApplicationEvent(ApplicationEvent event) { if(event instanceof ExRateChangeEvent){ System.out.println("工商银行收到->"+event.getSource()); } } }
spring-beans.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.lzyer.test"></context:component-scan> </beans>
测试代码
@Test public void testPublishEvent(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-beans.xml"); context.publishEvent(new ExRateChangeEvent("利息上调")); }
结果:
农业银行收到->利息上调
工商银行收到:->利息上调
事件原理流程
spring容器初始化调用的refresh方法
AbstractApplicationContext@refresh
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //省略 try { //省略 // 初始化广播事件 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. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { //省略 } } }
initApplicationEventMulticaster()注册广播事件
protected void initApplicationEventMulticaster() {
//获取beanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isDebugEnabled()) { logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else {//创建一个默认的事件广播器 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isDebugEnabled()) { logger.debug("Unable to locate ApplicationEventMulticaster with name '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "': using default [" + this.applicationEventMulticaster + "]"); } } }
AbstractApplicationEventMulticaster类中的属性
registerListeners方法
/** * Add beans that implement ApplicationListener as listeners. * Doesn't affect other listeners, which can be added without being beans. */ protected void registerListeners() { // Register statically specified listeners first. 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! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String lisName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(lisName); } }
在refresh最后的一个方法,中发布刷新事件。
finishRefresh
protected void finishRefresh() { // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event.发布刷新事件 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
事件整体结构图
最后走一波debug
参考资料
http://www.jianshu.com/p/bc1055b065ce
http://liuxiamai.iteye.com/blog/2322197
http://jinnianshilongnian.iteye.com/blog/1902886