Spring事件
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 源码解析
Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:
refresh()方法中有两个监听器相关的方法,分别是
- 创建事件多播器
initApplicationEventMulticaster(); 提供了容器监听器的注册表 - 将事件监听器注册到多播器上
registerListeners();
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 事件进行处理。