Spring自定义事件
Spring的自定义事件机制,为应用提供了便捷的解耦方式。Spring很多内置事件其实也都是自定义事件的一种实现,例如
Spring的一些内置事件 |
---|
ApplicationReadyEvent |
ApplicationStartedEvent |
ApplicationEnvironmentPreparedEvent |
Spring自定义事件是Spring Aware机制外的一大补充。
我们可以方便使用Spring 自定义事件来解耦程序,笔者就大量使用Spring自定义事件,在不同的模块间通信。由此在使用过程中衍生出了新的需求
需求起因
笔者在使用自定义事件时,通常一个事件有多个监听/订阅方。笔者是通过事件的传递机制,来控制一个初始化生命周期。在Spring中的一些实现中,也可以看到,在某个事件完成后,派发下一个事件。通过这种硬编码的方式,其实可以清晰知道一个事件是否完成。
//伪代码
//在一个事件中传递下一个事件
public void onApplicationEvent(RPCCompleteEvent event) {
ApplicationContext app = event.getApplicationContext();
AOPPreScanEvent aopPreScanEvent = new AOPPreScanEvent(event.getSource());
app.publishEvent(aopPreScanEvent);
}
但是这是硬编码的方式,必须在一个事件内部才能这样知道他的“完结”,并进行后续的逻辑。
其次,当一个事件有多个监听/订阅时,我们需要的是所有监听/订阅处理完毕后,继续逻辑处理,并且多个监听/订阅时,我们也无法在其中一个监听/订阅传递后续的逻辑,因为这里面可能涉及顺序问题。综上,我们需要一个在外部观察自定义事件执行情况的机制。
Spring自定义事件解析
通过源码解析可知,SimpleApplicationEventMulticaster中实际调用了ApplicationListener
//SimpleApplicationEventMulticaster.java
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//很容易就发现,自定义事件的执行逻辑。
//如果在上面植入一些before和after的钩子函数,岂不是完美解决?
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
所以,我们只需要在这里做改动即可。
SimpleApplicationEventMulticaster的扩展
用来添加before或after等钩子函数
//定义新的事件执行器
//扩展原来的SimpleApplicationEventMulticaster
public class SimpleApplicationEventMulticasterExtend extends SimpleApplicationEventMulticaster {
@Autowired
private ShinagawaSimpleApplicationEventInvokeListener shinagawaSimpleApplicationEventInvokeListener;
@Override
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
Executor executor = getTaskExecutor();
List<ApplicationListener<?>> applicationListenerList = getApplicationListeners(event, type).stream().collect(Collectors.toList());
shinagawaSimpleApplicationEventInvokeListener.setEventInvokeStatus(event.getClass(), ShinagawaSimpleApplicationEventInvokeListener.EventInvokeStatusEnum.START);
for (ApplicationListener<?> listener : applicationListenerList) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
if(executor==null) {
shinagawaSimpleApplicationEventInvokeListener.setEventInvokeStatus(event.getClass(), ShinagawaSimpleApplicationEventInvokeListener.EventInvokeStatusEnum.COMPLETE);
}else{
//多线程版本。暂时不考虑实现。
}
}
}
//用来管理事件的钩子函数
//你也可以实现你的版本
public class SimpleApplicationEventInvokeListener {
private static Map<Class,EventInvokeStatusEnum> EVENT_INVOKE_STATUS_MAP = new ConcurrentHashMap<>();
private static Map<Class,Boolean> EVENT_LISTENER_MAP = new ConcurrentHashMap<>();
private static final long delay = 100;
EventInvokeStatusEnum getEventInvokeStatus(Class event){
if(EVENT_INVOKE_STATUS_MAP.containsKey(event)){
return EVENT_INVOKE_STATUS_MAP.get(event);
}
return EventInvokeStatusEnum.UNKNOWN;
}
void setEventInvokeStatus(Class event,EventInvokeStatusEnum eventInvokeStatusEnum){
EVENT_INVOKE_STATUS_MAP.put(event,eventInvokeStatusEnum);
}
public void eventInvokeCompleteListener(Class event,Runnable runnable){
if(!EVENT_LISTENER_MAP.containsKey(event)){
EVENT_LISTENER_MAP.put(event,true);
ScheduledExecutorService scheduledExecutorService = ThreadPoolHelper.getSchedulePool(1,"eventListener-"+runnable.getClass().getName());
Runnable r = new EventCompleteCheckRunable(event,runnable,scheduledExecutorService);
scheduledExecutorService.schedule(r,delay, TimeUnit.MILLISECONDS);
}
}
class EventCompleteCheckRunable implements Runnable {
private Runnable callback = null;
private Class event;
private ScheduledExecutorService scheduledExecutorService = null;
public EventCompleteCheckRunable(Class event,Runnable callback,ScheduledExecutorService scheduledExecutorService) {
this.callback = callback;
this.event = event;
this.scheduledExecutorService = scheduledExecutorService;
}
@Override
public void run() {
try {
//log.info("线程:{}",Thread.currentThread().getName());
if (getEventInvokeStatus(event).equals(EventInvokeStatusEnum.COMPLETE)) {
scheduledExecutorService.shutdown();
EVENT_LISTENER_MAP.remove(event);
this.callback.run();
return;
}
//继续定时
scheduledExecutorService.schedule(this, delay, TimeUnit.MILLISECONDS);
}catch (Throwable e){
log.error("事件传播失败,异常:{}", ExceptionUtils.getStackTrace(e));
}
}
}
enum EventInvokeStatusEnum{
START, //事件准备开始执行
COMPLETE, //事件执行完成
UNKNOWN //未知
}
}
此时,相当于已经重新定义了Spring自定义事件的执行器,现在只需要将他添加到Spring中
植入专属SimpleApplicationEventMulticaster
根据源码可知,我们只需将扩展后的SimpleApplicationEventMulticaster命名为
APPLICATION_EVENT_MULTICASTER_BEAN_NAME
即可完成覆盖
//AbstractApplicationContext.java
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//当存在该bean时,则使用外部的自定义事件执行器
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() + "]");
}
}
}
//注入扩展后的事件执行器
@Bean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
public SimpleApplicationEventMulticasterExtend getSimpleApplicationEventMulticasterExtend(){
return new SimpleApplicationEventMulticasterExtend();
}
至此,我们可以在外部监听/订阅一个事件结束与否的信息了。。。
可以以无侵入的方式来执行我们的逻辑。
使用示例
//钩子函数定义
simpleApplicationEventInvokeListener.eventInvokeCompleteListener(AOPPreScanEvent.class, new Runnable() {
@Override
public void run() {
//AOPPreScanEvent事件执行完成后,想做的事
}
});
总结
这个需求产生于偶然。但是通过源码分析,发现Spring预留了如何替换SimpleApplicationEventMulticaster的扩展点,代表框架设计者想到了该场景。
代码只是样例,实际可能会有细微差别,本文仅是提供思路。请大家举一反三。