Spring内置事件
内置事件中由系统内部进行发布,只需注入监听器
自定义事件
事件类需要继承ApplicationEvent,代码如下:
public class BigEvent extends ApplicationEvent {
private String name;
public BigEvent(Object source, String name) {
super(source);
this.name = name;
}
public String getName() {
return name;
}
}
这里为了简单测试,所以写的很简单。
事件类是一种很简单的pojo,除了需要继承ApplicationEvent也没什么了,这个类有一个构造方法需要super。
事件监听器
事件监听器-基于接口
@Component
public class HelloEventListener implements ApplicationListener {
@Override
public void onApplicationEvent(OrderEvent event) {
if(event.getName().equals("减库存")){
System.out.println("减库存.......");
}
}
}
事件监听器需要实现ApplicationListener接口,这是个泛型接口,泛型类类型就是事件类型,其次需要是spring容器托管的bean,所以这里加了@component,只有一个方法,就是onApplicationEvent。
事件监听器-基于注解
@Component
public class OrderEventListener {
@EventListener(OrderEvent.class)
public void onApplicationEvent(OrderEvent event) {
if(event.getName().equals("减库存")){
System.out.println("减库存.......");
}
}
}
事件发布操作
事件发布方式很简单
applicationContext.publishEvent(new OrderEvent (this,"lgb"));
然后调用方法就能看到:
2. Spring事件原理
原理:观察者模式
spring的事件监听有三个部分组成:事件(ApplicationEvent) 负责对应相应监听器 事件源发生某事件是特定事件监听器被触发的原因。
监听器(ApplicationListener) 对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。
事件发布器(ApplicationEventMulticaster )对应于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。
Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:
也就是说上面代码中发布者调用applicationEventPublisher.publishEvent(msg); 是会将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。
源码流程:
Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。
AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。
AbstractApplicationContext在refresh()这个容器启动方法中搭建了事件的基础设施,其中AbstractApplicationContext的refresh方法实现如下:
事件的解析
(1) 实现接口 ApplicationListener bean的解析
AnnotationConfigApplicationContext
--> refresh
-->registerListeners
protected void registerListeners() {
//获取容器中所有的监听器对象
// 这个时候正常流程是不会有监听器的
// (因为监听器不会在这之前注册,在initApplicationEventMulticaster后在registerListeners之前,只有一个可能在:在onRefresh里面注册了监听器)
for (ApplicationListener> listener : getApplicationListeners()) {
//把监听器挨个的注册到我们的多播器上去
getApplicationEventMulticaster().addApplicationListener(listener);
}
//获取bean定义中的监听器对象
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
//把监听器的名称注册到我们的多播器上
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//在这里获取我们的早期事件
Set earlyEventsToProcess = this.earlyApplicationEvents;
// 在这里赋null。 也就是值此之后都将没有早期事件了
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
//通过多播器进行播发早期事件
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
还有就是 ApplicationListenerDetector 类的解析
ApplicationListenerDetector 实现 BeanPostProcessor接口
那么 ApplicationListenerDetector 在什么时候注册的呢?
refresh()-->prepareBeanFactory()方法
那么为什么前面registerListeners已经解析过了,为什么还要进行解析;
为了防止漏网之鱼;比如Bean 是个懒加载@Lazy注解,在registerListeners方法 是解析不到的。
(2) 使用 注解 @EventListener
解析类是 EventListenerMethodProcessor ,那么在哪注册的呢?
AnnotationConfigApplicationContext
--> this.reader = new AnnotatedBeanDefinitionReader(this);
//注册一些内置的后置处理器
-->AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
/**
* 处理监听方法的注解@EventListener解析器EventListenerMethodProcessor
*/
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
EventListenerMethodProcessor 实现了接口 SmartInitializingSingleton
那么在什么时候调用的呢?在初始化所有bean后调用
1 事件广播器的初始化
protected void initApplicationEventMulticaster() {
//获取我们的bean工厂对象
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断容器中是没有有我们的applicationEventMulticaster 应用多播器组件
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
//直接显示的调用我们的getBean获取出来赋值给我们的applicationContext对象
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
//容器中没有的话
else {
//spring ioc显示的new 一个SimpleApplicationEventMulticaster对象保存在applicatoinContext对象中
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
//并且注入到容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
用户可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster就可以了,Spring会通过 反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring自动使用 SimpleApplicationEventMulticaster作为事件广播器。
2 注册事件监听器
protected void registerListeners() {
//获取容器中所有的监听器对象
// 这个时候正常流程是不会有监听器的
// (因为监听器不会在这之前注册,在initApplicationEventMulticaster后在registerListeners之前,只有一个可能在:在onRefresh里面注册了监听器)
for (ApplicationListener> listener : getApplicationListeners()) {
//把监听器挨个的注册到我们的多播器上去
getApplicationEventMulticaster().addApplicationListener(listener);
}
//获取bean定义中的监听器对象
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
//把监听器的名称注册到我们的多播器上
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//在这里获取我们的早期事件
Set earlyEventsToProcess = this.earlyApplicationEvents;
// 在这里赋null。 也就是值此之后都将没有早期事件了
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));方法如下:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// 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();
}
}
// 这里是唯一添加早期事件的地方。所以一定要发布事件才能添加早期事件
// 只有当执行力refresh-->registerListeners 才会将earlyApplicationEvents赋为null,所以registerListeners之前发布的事件都是早期事件
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);
}
}
在AbtractApplicationContext的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;
}
@SuppressWarnings("unchecked")
public void multicastEvent(final ApplicationEvent event) {
for (Iterator it = getApplicationListeners().iterator(); it.hasNext();) {
final ApplicationListener listener = it.next();
getTaskExecutor().execute(new Runnable() {
public void run() {
listener.onApplicationEvent(event);
}
});
}
}
}
spring配置:
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster
= new SimpleApplicationEventMulticaster();
//ThreadPoolTaskExecutor
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
Spring发布事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。
Sping事件体系所使用的设计模式是:观察者模式。ApplicationListener是观察者接口,接口中定义了onApplicationEvent方法,该方法的作用是对ApplicationEvent事件进行处理。