简单描述
soul的数据同步分为2种方式
- Soul 网关在启动时会从从配置服务同步配置数据,并且支持推拉模式获取配置变更信息,并且更新本地缓存
- 管理后台发生变更通过推拉模式同步数据到网关.
soul如何实现同步
soul为了实现解耦采用的是spring事件监听机制 也就是观察者模式的一种实现.
Spring实现机制的主要相关类
1.ApplicationEventPublisher:发布事件;
2.ApplicationEvent:Spring 事件,记录事件源、时间和数据;
3.ApplicationListener:事件监听者,观察者;
soul发布事件
这里我主要看下插件的数据同步(其他数据的同步类似)
soul通过ApplicationEventPublisher的publishEvent方法发布需要变更的数据.
soul事件的实现
类 DataChangedEvent事件的信息.
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;
}
/**
* Gets event type.
*
* @return the event type
*/
DataEventTypeEnum getEventType() {
return eventType;
}
@Override
public List<?> getSource() {
return (List<?>) super.getSource();
}
/**
* Gets group key.
*
* @return the group key
*/
public ConfigGroupEnum getGroupKey() {
return this.groupKey;
}
}
从这类中我们可以看出主要包含的信息
1.groupKey(指定同步数据的分组ConfigGroupEnum(包含了选择器SELECTOR,规则RULE等))
2.eventType(指定操作的类型DataEventTypeEnum(包含了新增CREATE,更新UPDATE等))
3.List<?> source(我们需要操作的数据)
soul监听者实现
通过DataChangedEventDispatcher进行转发
先看下类的关系图
public class DataChangedEventDispatcher implements ApplicationListener<DataChangedEvent>, InitializingBean {
private ApplicationContext applicationContext;
//注册的监听者
private List<DataChangedListener> listeners;
public DataChangedEventDispatcher(final ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
@SuppressWarnings("unchecked")
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());
}
}
}
@Override
public void afterPropertiesSet() {
Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
}
}
我们可以看到变量里保存了监听者的信息
private List listeners;
事件有改动的时候就会循环通知监听者
监听者如果注册的
在这里soul采用了spring注册最简单的方式,
把监听器部署到ApplicationContext,实际上就是将将监听器交给Spring 容器管理,所以最简单的方法只需在自定义的上加上@Component注解
soul如果通过配置yml文件实现不同注册监听者
这里我们可以看下DataSyncConfiguration类中实现
我们可以看到实现了不同监听者的配置.
通过@ConditionalOnProperty注解中是否包含的信息来判断这个配置注解是否生效.
@Configuration
@ConditionalOnProperty(name = "soul.sync.http.enabled", havingValue = "true")
@EnableConfigurationProperties(HttpSyncProperties.class)
static class HttpLongPollingListener {
@Bean
@ConditionalOnMissingBean(HttpLongPollingDataChangedListener.class)
public HttpLongPollingDataChangedListener httpLongPollingDataChangedListener(final HttpSyncProperties httpSyncProperties) {
return new HttpLongPollingDataChangedListener(httpSyncProperties);
}
}
至此已经完成了数据同步的简单分析.