spring中的事件监听机制

Spring event listener

      • 介绍
        • example
        • 简单原理解释
      • 自定义事件、监听和发布
        • 事件
        • 监听器
        • 发布者
        • 测试
      • 更加一般的事件
        • @EventListener原理

介绍

example

spring支持自定义的事件发布。

spring的事件监听机制基于ApplicationListener这个接口。

/*
Interface to be implemented by application event listeners.Based on the standard {@code java.util.EventListener} interface
for the Observer design pattern. As of Spring 3.0, an ApplicationListener can generically declare the event type that it is interested in. When registered with a Spring ApplicationContext, events will be filtered accordingly, with the listener getting invoked for matching event objects only.
*/

这个接口继承了 java.util.EventListener。基于观察者模式。

ApplicationListener 的实现类会在spring容器启动的时候被发现。


我们可以简单的看一下spring它自带的ApplicationListener

@Component
public class MyEventListener implements ApplicationListener {
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		System.out.println("event source: " + event.getSource());
		System.out.println("event: " + event.toString());
	}
}

在这里我们打印事件源和ApplicationEvent本身。

启动容器:

public class SpringEventsTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = 
		new AnnotationConfigApplicationContext(SpringEventsConfig.class);
	}
}

控制台:

event source: org.springframework.context.annotation.
AnnotationConfigApplicationContext@23fc625e, 
started on Sat Jun 20 21:20:00 GMT+08:00 2020

event: org.springframework.context.event.
ContextRefreshedEvent[source=org.springframework.context.annotation.
AnnotationConfigApplicationContext@23fc625e, 
started on Sat Jun 20 21:20:00 GMT+08:00 2020


事件源就是AnnotationConfigApplicationContext,事件是ContextRefreshedEvent

其实我们还可以看到一个关闭事件,加上一句话:

AnnotationConfigApplicationContext ac = 
new AnnotationConfigApplicationContext(SpringEventsConfig.class);
ac.close();

这时候的日志就多了一个关闭事件:

event source: org.springframework.context.annotation.
AnnotationConfigApplicationContext@244038d0, 
started on Wed Jun 08 17:27:50 CST 2022

event: org.springframework.context.event.
ContextClosedEvent[source=org.springframework.context.annotation.
AnnotationConfigApplicationContext@244038d0, 
started on Wed Jun 08 17:27:50 CST 2022]

简单原理解释

我们可以稍稍看一下调用链,先打一个断点:

spring中的事件监听机制_第1张图片

spring中的事件监听机制_第2张图片
事件发布是refresh的最后一个方法。

spring中的事件监听机制_第3张图片

将刷新事件传入publishEvent中。

spring中的事件监听机制_第4张图片
他去获取了一个Multicaster(广播器)去广播事件。

spring中的事件监听机制_第5张图片
但是我们似乎不知道这个applicationEventMulticaster是从什么时候赋值的(先假设有值了)。

spring中的事件监听机制_第6张图片

spring中的事件监听机制_第7张图片

然后他获取所有的监听器,依次调用他们的回调方法onApplicationEvent

现在又有问题了:

spring中的事件监听机制_第8张图片

在我去获取监听器的时候就已经能够获取到了,那么这些监听器是何时加到spring容器中的呢?


我们首先看看那个广播器是如何加入到容器中的?

spring中的事件监听机制_第9张图片

spring中的事件监听机制_第10张图片

这个东西是new出来然后干到容器中的。

spring中的事件监听机制_第11张图片
spring中的事件监听机制_第12张图片

它通过getBeanNamesForType获取到了我们自定义的监听器,当然这不能说监听器放进了spring容器中,只能说广播器获取到了我们自定义的监听器。

自定义事件、监听和发布

事件

public class CustomSpringEvent extends ApplicationEvent {
	private static final long serialVersionUID = -8053143381029977953L;

	private String message;

	public CustomSpringEvent(final Object source, final String message) {
		super(source);
		this.message = message;
	}

	public String getMessage() {
		return message;
	}

}

自定义事件需要继承ApplicationEvent

监听器

有了事件之后,我们需要一个监听器来监听事件:

@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {

	@Override
	public void onApplicationEvent(final CustomSpringEvent event) {
		System.out.println("Received spring custom event - " + event.getMessage());
	}

}

自定义监听器要实现ApplicationListener接口。

onApplicationEvent方法最终会被spring回调,它的含义是消费事件。

发布者

一个事件必须要基于发布者才能够发布,如此才能被监听器监听到:

@Component
public class CustomSpringEventPublisher implements ApplicationEventPublisherAware {

	private ApplicationEventPublisher applicationEventPublisher;

	public void publishEvent(final String message) {
		System.out.println("Publishing custom event. ");
		final CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
		applicationEventPublisher.publishEvent(customSpringEvent);
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
	}
}

发布者要实现ApplicationEventPublisherAware接口。

我们将spring容器传进来的ApplicationEventPublisher保存起来,然后调用它的api发布事件。

测试

我们从容器中拿到发布者,然后发布事件。spring会自动监听到,然后消费事件:


public class SpringEventsTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringEventsConfig.class);
		CustomSpringEventPublisher customSpringEventPublisher = applicationContext.getBean("customSpringEventPublisher", CustomSpringEventPublisher.class);
		customSpringEventPublisher.publishEvent("lalala");
	}
}

结果:

Publishing custom event. 
Received spring custom event - lalala

更加一般的事件

实际上,一个事件并不用继承ApplicationEvent。我们可以写一个任意的事件:

public class GenericSpringEvent<T> {

	private final T what;
	protected final boolean success;

	public GenericSpringEvent(final T what, final boolean success) {
		this.what = what;
		this.success = success;
	}

	public T getWhat() {
		return what;
	}

	public boolean isSuccess() {
		return success;
	}

}

这个事件包含事件是什么以及是否被成功消费

为了表示可扩展性,我们写一个具体的String事件来继承它:

public class GenericStringSpringEvent extends GenericSpringEvent<String> {

	GenericStringSpringEvent(final String what, final boolean success) {
		super(what, success);
	}

}

这种情况的监听器比较特殊,我们必须用@EventListener注解来标注:

@Component
public class AnnotationDrivenEventListener {
	private boolean hitSuccessfulEventHandler = false;
	
	@EventListener(condition = "#event.success")
	public void handleSuccessful(final GenericSpringEvent<String> event) {
		System.out.println("Handling generic event (conditional): " + event.getWhat());
		hitSuccessfulEventHandler = true;
	}
}

这个注解上面我们还附加了条件,使用的是SpEl表达式。

只有conditiontrue,才能回调handleSuccessful方法。


至于事件的发布,与之前讲的自定义事件发布是一样的:

	public void publishGenericEvent(final String message, boolean success) {
		System.out.println("Publishing generic event.");
		final GenericSpringEvent<String> genericSpringEvent = new GenericStringSpringEvent(message, success);
		applicationEventPublisher.publishEvent(genericSpringEvent);
	}

测试:

public class SpringEventsTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringEventsConfig.class);
		CustomSpringEventPublisher customSpringEventPublisher = applicationContext.getBean("customSpringEventPublisher", CustomSpringEventPublisher.class);
		customSpringEventPublisher.publishGenericEvent("generic event",true);
	}
}

结果:

Publishing generic event.
Handling generic event (conditional): generic event

如果发布事件的时候将success改为false

customSpringEventPublisher.publishGenericEvent("generic event",false);

那么发布的事件将无法被监听到。

@EventListener原理

为什么一个bean加了@EventListener注解就能后监听到事件呢?换句话说,这个注解是由谁解析的,时机又是在什么时候。

spring中的事件监听机制_第13张图片
我们需要关注一个类:EventListenerMethodProcessor

spring中的事件监听机制_第14张图片
他是一个什么呢?他是一个SmartInitializingSingleton,这个东西就出现在bean的生命周期里了。

spring中的事件监听机制_第15张图片

在完成bean的创建后,还要进行一步判断,看这个bean是不是SmartInitializingSingleton

spring中的事件监听机制_第16张图片
此时我们的EventListenerMethodProcessor就会进来解析。

你可能感兴趣的:(spring,spring,event,java,事件发布,观察者模式)