java 事件类型_Spring框架中有哪些不同类型的事件?

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事件进行处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值