soul网关学习六之soul-admin使用websocket同步数据到网关

soul-admin 可以使用websocket与soul-bootstrap进行通信

1.配置

引入 jar 包
在这里插入图片描述
soul-admin中配置 websocket
在这里插入图片描述

soul-bootstrap中配置websokcet的地址
在这里插入图片描述

2. soul-admin 配置加载

soul-admin 端会加载一个 WebsocketDataChangedListener , 该类中使用 WebsocketCollector 连接 websocket 来发送数据给 soul-bootstrap
在这里插入图片描述
在这里插入图片描述
admin端使用spring的事件注册机制在更改配置时发送事件,将修改的配置发送出去
每个service都会注入 eventPublisher 用来发布配置修改的事件 DataChangedEvent
在这里插入图片描述
在这里插入图片描述
DataChangedEventDispatcher 用来接收 DataChangedEvent 事件,该类会加载容器内配置的 DataChangedListener
在这里插入图片描述

public class DataChangedEventDispatcher implements ApplicationListener<DataChangedEvent>, InitializingBean {
    private ApplicationContext applicationContext;
    private List<DataChangedListener> listeners;
    public DataChangedEventDispatcher(final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
//  接收 DataChangedEvent事件后使用循环DataChangedListener处理事件 
    @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());
            }
        }
    }
    // 获取容器中的 DataChangedListener
    @Override
    public void afterPropertiesSet() {
        Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
        this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
    }
}

因为我们使用的是 websocket, 我们以 RULE 为例,当接收到DataChangedEvent事件时就会调用 WebsocketDataChangedListener.onRuleChanged()

 @Override
    public void onRuleChanged(final List<RuleData> ruleDataList, final DataEventTypeEnum eventType) {
        WebsocketData<RuleData> configData =
                new WebsocketData<>(ConfigGroupEnum.RULE.name(), eventType.name(), ruleDataList);
        WebsocketCollector.send(GsonUtils.getInstance().toJson(configData), eventType);
    }

在这里使用 WebsocketCollector发送数据

3.soul-boostrap配置加载

在项目启动时会在 WebsocketSyncDataConfiguration 中注册
websocketConfig websocket 配置
pluginSubscriber 用于广播plugin的改动
metaSubscribers 用于广播 metaData的改动
authSubscribers 用于改动 auth的改动
在这里插入图片描述
看下 WebsocketSyncDataService 构造方法

public WebsocketSyncDataService(final WebsocketConfig websocketConfig,
                                    final PluginDataSubscriber pluginDataSubscriber,
                                    final List<MetaDataSubscriber> metaDataSubscribers,
                                    final List<AuthDataSubscriber> authDataSubscribers) {
//        配置的 soul-admin url,可能为多个
        String[] urls = StringUtils.split(websocketConfig.getUrls(), ",");
//        创建一个定时线程池,用于定时重连 soul-admin
        executor = new ScheduledThreadPoolExecutor(urls.length, SoulThreadFactory.create("websocket-connect", true));
        for (String url : urls) {
            try {
//                为 每一个 soul-admin url 创建一个 SoulWebsocketClient
                clients.add(new SoulWebsocketClient(new URI(url), Objects.requireNonNull(pluginDataSubscriber), metaDataSubscribers, authDataSubscribers));
            } catch (URISyntaxException e) {
                log.error("websocket url({}) is error", url, e);
            }
        }
        try {
//            遍历创建的 WebSocketClient 判断是否与 websocket 客户端相连
            for (WebSocketClient client : clients) {
                boolean success = client.connectBlocking(3000, TimeUnit.MILLISECONDS);
                if (success) {
                    log.info("websocket connection is successful.....");
                } else {
                    log.error("websocket connection is error.....");
                }
//                线程池 定时连接客户端,避免掉线
                executor.scheduleAtFixedRate(() -> {
                    try {
                        if (client.isClosed()) {
                            boolean reconnectSuccess = client.reconnectBlocking();
                            if (reconnectSuccess) {
                                log.info("websocket reconnect is successful.....");
                            } else {
                                log.error("websocket reconnection is error.....");
                            }
                        }
                    } catch (InterruptedException e) {
                        log.error("websocket connect is error :{}", e.getMessage());
                    }
                }, 10, 30, TimeUnit.SECONDS);
            }
            /* client.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyaddress", 80)));*/
        } catch (InterruptedException e) {
            log.info("websocket connection...exception....", e);
        }
    }


SoulWebsocketClient 中会初始化 WebsocketDataHandler , 内部缓存 5中数据的DataHandler用来更新客户端修改的数据。在这里插入图片描述
在这里插入图片描述

3.使用websocket同步数据

当soul-admin修改数据时就会调用 SoulWebsocketClient.onMessage() 方法
在这里插入图片描述

在这里插入图片描述
WebsocketDataHandler 中根据启动加载缓存的具体 handler 处理数据。我们这里修改的是 rule 类型,所以会调用 RuleDataHandler.handle() 方法
在这里插入图片描述
因为是 ruleDate的update 最后调用 CommonPluginDataSubscriber.onRuleSubscribe() 来更新 ruleData
在这里插入图片描述
执行 subscribeDataHandler 更新缓存中的 ruleData

private <T> void subscribeDataHandler(final T classData, final DataEventTypeEnum dataType) {
        Optional.ofNullable(classData).ifPresent(data -> {
            if (data instanceof PluginData) {
 //                省略
            } else if (data instanceof SelectorData) {
//                省略
            } else if (data instanceof RuleData) {
                RuleData ruleData = (RuleData) data;
                if (dataType == DataEventTypeEnum.UPDATE) {
//                    更新本地缓存的 ruleData
                    BaseDataCache.getInstance().cacheRuleData(ruleData);
                    Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.handlerRule(ruleData));
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    BaseDataCache.getInstance().removeRuleData(ruleData);
                    Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.removeRule(ruleData));
                }
            }
        });
    }

到这里 soul-admin 通过websocket 更新ruleData的流程就结束啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值