soul入门 第七章 admin和网关数据同步之zookeeper

341 阅读2分钟

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))));

总结:这里主要用到观察者模式,把调用方和被调用方解藕,非常灵活。