Spring的高级容器接口继承了ApplicationEventPublisher接口,说明其具备了事件发布的能力,这里就介绍下Spring的事件功能。不过说实话,这个功能貌似很鸡肋,没见过使用场景。但是不影响我们抱着学习的态度研究下。
首先看下接口定义:
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
只有一个方法。
再看下如何使用:
Spring容器仅仅是负责事件的发布,所以还有一个重要角色是事件的监听者,另外,事件类也是可以扩展的。
先看下监听者接口定义:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
该接口继承了jdk的EventListener。
定义一个我们的自己的实例监听器:
public class MyListener implements ApplicationListener<MyEvent> {
public void onApplicationEvent(MyEvent event) {
System.out.println(event.getSource());
}
}
需要把监听器的bean交给Spring统一管理起来:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.liyao.listener.MyListener"/>
</beans>
可以看到,这里我们也定义了一个自己的事件类叫做MyEvent:
public class MyEvent extends ApplicationEvent {
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
public MyEvent(Object source) {
super(source);
}
}
事件类需要统一继承自Spring提供的ApplicationEvent类。
而ApplicationEvent类又是继承自jdk的EventObject类。
并且,java中推荐所有的事件和监听器都继承EventObject和EventListener,算是一种约定俗成吧。
然后写一个main:
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
MyEvent event = new MyEvent("test");
context.publishEvent(event);
}
输出:
test
Process finished with exit code 0
最后看下原理部分
ApplicationEventPublisher接口是由AbstractApplicationContext抽象类实现的:
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
/**
* 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, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// 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();
}
}
// 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);
}
}
}
可以看到,里面其实调用了一个event multicaster来发送消息的:
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
return this.applicationEventMulticaster;
}
那么这个applicationEventMulticaster变量是什么时候赋值的呢?
是在refresh时调用的这个方法:
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.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
可以看到,这里其实是new了一个SimpleApplicationEventMulticaster实例。
实际的发送逻辑就是拿出所有的ApplicationListener的bean,依次回调,具体的代码就不贴了。