赞
踩
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]
我们可以稍稍看一下调用链,先打一个断点:
事件发布是refresh
的最后一个方法。
将刷新事件传入publishEvent
中。
他去获取了一个Multicaster(广播器)
去广播事件。
但是我们似乎不知道这个applicationEventMulticaster
是从什么时候赋值的(先假设有值了)。
然后他获取所有的监听器,依次调用他们的回调方法onApplicationEvent
。
现在又有问题了:
在我去获取监听器的时候就已经能够获取到了,那么这些监听器是何时加到spring容器中的呢?
我们首先看看那个广播器是如何加入到容器中的?
这个东西是new
出来然后干到容器中的。
它通过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表达式。
只有condition
为true
,才能回调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);
那么发布的事件将无法被监听到。
为什么一个bean加了@EventListener
注解就能后监听到事件呢?换句话说,这个注解是由谁解析的,时机又是在什么时候。
我们需要关注一个类:EventListenerMethodProcessor
。
他是一个什么呢?他是一个SmartInitializingSingleton
,这个东西就出现在bean的生命周期里了。
在完成bean的创建后,还要进行一步判断,看这个bean是不是SmartInitializingSingleton
。
此时我们的EventListenerMethodProcessor
就会进来解析。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。