Spring思维导图
Spring事件体系包括三个组件:事件,事件监听器,事件广播器
首先需要了解什么是:观察者模式
Event | 说明 |
---|---|
ContextRefreshedEvent | 当容器被实例化或refreshed时发布.如调用refresh()方法, 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化, 所有的容器对象都已准备好可使用. 如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)利用此内置事件可以在所有的Bean都创建完成后做扩展代码 |
ContextStartedEvent | 当容器启动时发布,即调用start()方法, 已启用意味着所有的Lifecycle bean都已显式接收到了start信号 |
ContextStoppedEvent | 当容器停止时发布,即调用stop()方法, 即所有的 Lifecycle bean都已显式接收到了stop信号 , 关闭的容器可以通过start()方法重启 |
ContextClosedEvent | 当容器关闭时发布,即调用close方法, 关闭意味着所有的单例bean都已被销毁.关闭的容器不能被重启或refresh |
RequestHandledEvent | 这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布 |
1、事件类继承 ApplicationEvent,构造方法 super(Object source)
// 事件类继承 ApplicationEvent ,构造方法 super public class OrderEvent extends ApplicationEvent implements Serializable { private static final long serialVersionUID = -724777220496990061L; private String name; public OrderEvent(Object source, String name) { super(source); this.name = name; } public String getName() { return name; } }
2、事件监听器 又分为两种(基于接口、基于注解) ,需要是 Spring 容器托管的 bean 需要加上 @Component 注解,只有一个方法 onApplicationEvent
基于接口:
@Component @Lazy public class OrderEventListener implements ApplicationListener<OrderEvent> { @Override public void onApplicationEvent(OrderEvent event) { if(event.getName().equals("Inventory reduction")){ System.out.println("Inventory reduction......."); } } }
基于注解:
@Component @Lazy public class OrderEventListener { // 基于注解的 @EventListener(OrderEvent.class) public void onApplicationEvent(OrderEvent event) { if(event.getName().equals("Inventory reduction")){ System.out.println("Inventory reduction......."); } } }
3、发布事件 publishEvent((ApplicationEvent event)
public class MainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig2.class); //下单 Order order =new Order(); order.setId(1); System.out.println("place the order"); // 减库存 // 发布事件 ctx.publishEvent(new OrderEvent(order,"Inventory reduction")); // 日志 System.out.println("other..."); } } ---------------运行结果----------------- place the order Inventory reduction....... other...
注意的点:
Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:
refresh()方法中有两个监听器相关的方法,分别是
try { // 4:空方法 // 留给子类去实现该接口 允许在上下文子类中对Bean工厂进行后置处理。 postProcessBeanFactory(beanFactory); // 5:调用Bean工厂的后置处理器 // 执行自定义的BeanFactoryPostProcessor和内置的BeanFactoryPostProcessor // 此方法会实例化几个内置的Bean实例化 invokeBeanFactoryPostProcessors(beanFactory); // 6:调用Bean的后置处理器,此处也会实例化几个内置的Bean registerBeanPostProcessors(beanFactory); // 7:初始化国际化资源处理器. initMessageSource(); // 8:创建事件多播器 initApplicationEventMulticaster(); // 9:这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的. onRefresh(); // 10:将事件监听器注册到多播器上 registerListeners(); // 11:实例化懒加载单例Bean的,也就是我们的Bean都是在这里被创建出来的(绝大部分情况) finishBeanFactoryInitialization(beanFactory); // 12:最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的) finishRefresh(); }
1、事件广播器的初始化
/** * Initialize the ApplicationEventMulticaster. * Uses SimpleApplicationEventMulticaster if none defined in the context. * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ 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.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 + "]"); } } }
用户可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster
就可以了,Spring 会通过反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring 自动使用SimpleApplicationEventMulticaster
作为事件广播器。
2、注册事件监听器
/** * 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 listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
Spring 根据反射机制,使用 ListableBeanFactory 的getBeansOfType()
方法,从 BeanDefinitionRegistry 中找出所有实现org.springframework.context.ApplicationListener
的 Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。
3、发布事件
跟着finishRefresh();
方法进入publishEvent(new ContextRefreshedEvent(this));
方法如下:
/** * Publish the given event to all listeners. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) * @param eventType the resolved event type, if known * @since 4.2 */ protected void publishEvent(Object event, ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); } // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<Object>(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 将事件通知给所有的事件监听器.
4 、Spring默认的事件广播器SimpleApplicationEventMulticaster
@Override public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } } /** * Invoke the given listener with the given event. * @param listener the ApplicationListener to invoke * @param event the current event to propagate * @since 4.1 */ @SuppressWarnings({"unchecked", "rawtypes"}) protected void invokeListener(ApplicationListener listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { listener.onApplicationEvent(event); } catch (Throwable err) { errorHandler.handleError(err); } } else { try { listener.onApplicationEvent(event); } catch (ClassCastException ex) { // Possibly a lambda-defined listener which we could not resolve the generic event type for LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex); } } }
遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法。由于SimpleApplicationEventMulticaster
的taskExecutor的实现类是 SyncTaskExecutor,因此,事件监听器对事件的处理,是同步进行的
从源码可以看出applicationContext.publishEvent()
方法,需要同步等待各个监听器处理完之后,才返回。也就是说,Spring 提供的事件机制,默认是同步的。如果想用异步的,可以自己实现ApplicationEventMulticaster
接口,并在Spring 容器中注册 id 为 applicationEventMulticaster 的 Bean。
public class AsyncApplicationEventMulticaster extends AbstractApplicationEventMulticaster { private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); public void setTaskExecutor(TaskExecutor taskExecutor) { this.taskExecutor = (taskExecutor != null ? taskExecutor : new SimpleAsyncTaskExecutor()); } protected TaskExecutor getTaskExecutor() { return this.taskExecutor; } public void multicastEvent(final ApplicationEvent event) { for (Iterator<ApplicationListener> it = getApplicationListeners().iterator(); it.hasNext();) { final ApplicationListener listener = it.next(); getTaskExecutor().execute(new Runnable() { public void run() { listener.onApplicationEvent(event); } }); } } }
@Bean(name = "applicationEventMulticaster") public ApplicationEventMulticaster simpleApplicationEventMulticaster() { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); //ThreadPoolTaskExecutor eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return eventMulticaster; }
Spring发布事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。Sping 事件体系所使用的设计模式是:观察者模式。ApplicationListener 是观察者接口,接口中定义了onApplicationEvent()
方法,该方法的作用是对 ApplicationEvent 事件进行处理。