soul入门 第七章 admin和网关数据同步之zookeeper
-
admin和网关数据通信简概
admin第一次会全量以及气候的修改的数据都会推送到zk,而网关也会连接上zk并watch,数据每有改变都同步到网关。zk成为admin和网关沟通的桥梁。
-
admin 引入zookeeper
<dependency> <!-- zookeeper 客户端 --> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency>
## 配置zookeeper路径等
sync:
zookeeper:
url: localhost:2181
sessionTimeout: 5000
connectionTimeout: 2000
初始化zookeeper必须的类
@Configuration
@ConditionalOnProperty(prefix = "soul.sync.zookeeper", name = "url")
@Import(ZookeeperConfiguration.class)
static class ZookeeperListener {
// 初始化事件处理器
@Bean
@ConditionalOnMissingBean(ZookeeperDataChangedListener.class)
public DataChangedListener zookeeperDataChangedListener(final ZkClient zkClient) {
return new ZookeeperDataChangedListener(zkClient);
}
// 初始化数据到zookeeper
@Bean
@ConditionalOnMissingBean(ZookeeperDataInit.class)
public ZookeeperDataInit zookeeperDataInit(final ZkClient zkClient, final SyncDataService syncDataService) {
return new ZookeeperDataInit(zkClient, syncDataService);
}
}
当有数据改动的时候,程序是如何让ZookeeperDataChangedListener去获取到修改的数据,然后推送到zookeeper的呢?
先来看个接口
public interface DataChangedListener {
default void onAppAuthChanged(List<AppAuthData> changed, DataEventTypeEnum eventType) {
}
default void onPluginChanged(List<PluginData> changed, DataEventTypeEnum eventType) {
}
default void onSelectorChanged(List<SelectorData> changed, DataEventTypeEnum eventType) {
}
default void onMetaDataChanged(List<MetaData> changed, DataEventTypeEnum eventType) {
}
default void onRuleChanged(List<RuleData> changed, DataEventTypeEnum eventType) {
}
}
这接口定义了对各种数据变化的处理界面,提供给相应通信方式去实现ZookeeperDataChangedListener类实现了它,上一章讲的websocket通信方式同样有一个类去实现它。
那ZookeeperDataChangedListener里面的具体方法是怎么被调用的呢?且看类DataChangedEventDispatcher,该类实现接口ApplicationListener接受DataChangedEvent事件,当触发DataChangedEvent事件,onApplicationEvent方法会被执行,并且事件参数被传入,该事件参数其实是对修改的数据的封装
@Component
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() {
// 初始化时注入实现DataChangedListener接口的类
Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
}
}
在什么情况下会触发事件呢?数据改动逻辑里都有如下代码片段,可以确定就是它触发了事件
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, eventType,
Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDTO))));
总结:这里主要用到观察者模式,把调用方和被调用方解藕,非常灵活。