话不多说,上来就干
背景
在跟读soul源码的过程中,发现很多监听器,这些监听器是基于事件触发机制,而soul本身是采用响应式编程,网络框架采用netty。这其中都绕不开事件机制,而在java中,spring通过实现java.util.EventObject
接口,来设计事件抽象类应用事件ApplicationEvent
,这个接口中只有一个成员变量source
,表示事件初始化发生时的对象
/**
* The object on which the Event initially occurred.
*/
protected transient Object source;
soul中的观察者模式之发布监听模式
soul源码中,DataChangedEvent
继承spring的应用事件抽象类,并增加了两个成员变量
public class DataChangedEvent extends ApplicationEvent {
/**
* 数据事件类型
* 包含增删改查等一系列对数据的操作
*/
private DataEventTypeEnum eventType;
/**
* 配置组
* 业务维度上的数据模型
* 包含了权限/插件/规则/选择器等
*/
private ConfigGroupEnum groupKey;
/**
* Instantiates a new Data changed event.
*
* @param groupKey the group key
* @param type the type
* @param source the source
*/
public DataChangedEvent(final ConfigGroupEnum groupKey, final DataEventTypeEnum type, final List<?> source) {
super(source);
this.eventType = type;
this.groupKey = groupKey;
}
}
之所以增加两个成员变量,是因为需要通过这两个成员变量控制数据变更事件的类型,用于数据链路后的DataChangedEventDispatcher
类进行匹配分发给不同的监听器,处理不同的逻辑。
EventPublisher 事件发布者
在soul的admin服务中,对于数据的写操作,基本逻辑都遵循 修改admin服务数据库数据或缓存
-> 发布数据变更事件
-> 后续逻辑
....
public String createOrUpdate(final PluginDTO pluginDTO) {
//admin数据逻辑
final String msg = checkData(pluginDTO);
if (StringUtils.isNoneBlank(msg)) {
return msg;
}
PluginDO pluginDO = PluginDO.buildPluginDO(pluginDTO);
DataEventTypeEnum eventType = DataEventTypeEnum.CREATE;
if (StringUtils.isBlank(pluginDTO.getId())) {
pluginMapper.insertSelective(pluginDO);
} else {
eventType = DataEventTypeEnum.UPDATE;
pluginMapper.updateSelective(pluginDO);
}
// 发布数据变更事件
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, eventType,
Collections.singletonList(PluginTransfer.INSTANCE.mapToData(pluginDO))));
return StringUtils.EMPTY;
}
eventPublisher
就是spring注入的应用发布者ApplicationEventPublisher
,这个接口被函数式编程接口注解修饰@FunctionalInterface
,表面这是一个函数式接口,只有一个抽象方法,另个default方法,相当于约束了唯一的抽象方法的参数类型为ApplicationEvent
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
具体实现
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);
}
}
}
其中,multicastEvent(applicationEvent, eventType)
是直接执行传播事件的方法
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//获取并发线程执行器
Executor executor = getTaskExecutor();
// 获取event类型对应的监听器,并循环调用监听器的监听方法
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
// 调用对应的事件的监听器,通过线程池中的可用线程执行
executor.execute(() -> invokeListener(listener, event));
}
else {
// 调用对应事件的监听器,直接使用mian线程执行
invokeListener(listener, event);
}
}
}
直接调用具体类型实现类的onApplicationEvent()
方法,这个方法就是监听者重写的方法,重写内容为监听到相关信息所做的具体逻辑处理
DataChangedListener 事件监听者
实际上在调用具体的监听者之前,还会通过DataChangedEventDispatcher
调度器分发到具体的数据变更事件逻辑,继续处理
public void onApplicationEvent(final DataChangedEvent event) {
for (DataChangedListener listener : listeners) {
switch (event.getGroupKey()) {
case APP_AUTH:
listener.onAppAuthChanged((List<AppAuthData>) event.getSource(), event.getEventType());
break;
case PLUGIN:
listener.onPluginChanged((List<PluginData>) event.getSource(), event.getEventType());
break;
case RULE:
listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
break;
case SELECTOR:
listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
break;
case META_DATA:
listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType());
break;
default:
throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
}
}
}