Soul网关源码学习03

Soul网关源码学习03

soul-admin数据同步

soul-admin 使用 websocket 的方式实现数据同步,会保存与客户端的 session 信息在集合中,数据的更新以广播或单播的方式对soul-web进行通知。

DataSyncConfiguration

数据同步的方式,支持多种的配置,先看配置 websocket 的方式。

@Configuration
//使用websocket同步的开关
@ConditionalOnProperty(name = "soul.sync.websocket.enabled", havingValue = "true")
@EnableConfigurationProperties(WebsocketSyncProperties.class)
static class WebsocketListener {
	//发送通知事件的实现类WebsocketDataChangedListener
    @Bean
    @ConditionalOnMissingBean(WebsocketDataChangedListener.class)
    public DataChangedListener websocketDataChangedListener() {
        return new WebsocketDataChangedListener();
    
	//Websocket服务端
    @Bean
    @ConditionalOnMissingBean(WebsocketCollector.class)
    public WebsocketCollector websocketCollector() {
        return new WebsocketCollector();
    }
 	//使用@ServerEndpoint注解需要实例化ServerEndpointExporter
    @Bean
    @ConditionalOnMissingBean(ServerEndpointExporter.class)
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

1、soul.sync.websocket.enabled=true 使用websocket同步的开关。
2、实例化发送通知事件的实现类,实例化websocket服务端。
3、使用容器中使用@ServerEndpoint,需要单独的声明ServerEndpointExporte。

WebsocketCollector

使用注解的方式,对 websocket 请求进行处理。

@Slf4j
@ServerEndpoint("/websocket")
public class WebsocketCollector {
    private static final Set<Session> SESSION_SET = new CopyOnWriteArraySet<>();
    private static Session session;
    //建立连接
    @OnOpen
    public void onOpen(final Session session) {
        log.info("websocket on open successful....");
        SESSION_SET.add(session);
    }
    //收到客户端消息
    @OnMessage
    public void onMessage(final String message, final Session session) {
        if (message.equals(DataEventTypeEnum.MYSELF.name())) {
            WebsocketCollector.session = session;
            //数据同步事件
            SpringBeanUtils.getInstance().getBean(SyncDataService.class).syncAll(DataEventTypeEnum.MYSELF);
        }
    }
    //连接关闭
    @OnClose
    public void onClose(final Session session) {
        SESSION_SET.remove(session);
        WebsocketCollector.session = null;
    }
    //发生错误
    @OnError
    public void onError(final Session session, final Throwable error) {
        SESSION_SET.remove(session);
        WebsocketCollector.session = null;
        log.error("websocket collection error: ", error);
    }
    //消息发送
	public static void send(String message, DataEventTypeEnum type) {
		if (StringUtils.isNotBlank(message)) {
            if (DataEventTypeEnum.MYSELF == type) {
                try {
                    //单个发送
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.error("websocket send result is exception: ", e);
                }
                return;
            }
            //广播的方式
            for (Session session : SESSION_SET) {
                try {
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.error("websocket send result is exception: ", e);
                }
            }
        }
    }
}

1、使用静态变量保存 Session 并发的场景存在bug,所以我已经向 soul 提了PR,并且已经合并。
2、解决办法就是使用 ThreadLocal 保存 Session 信息,同步结束后删除,避免OOM。

DataChangedEventDispatcher

使用观察者模式对数据的更新进行事件监听。

@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() {
        Collection<DataChangedListener> listenerBeans = applicationContext.getBeansOfType(DataChangedListener.class).values();
        this.listeners = Collections.unmodifiableList(new ArrayList<>(listenerBeans));
    }
}

1、实现InitializingBean接口,获得所有接口的实现类,说明soul支持多协议的通知。
2、监听到DataChangedEvent事件,循环所有协议根据事件类型进行通知。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值