结合sofa插件,发起http请求soul网关,体验sofa代理
一、启动服务:
-
soul-admin
-
soul-bootstrap
soul-examples-sofa 启动报如下错误,同时会影响网关测的服务调用,导致服务无法调通。
- 解决方式:这里的 bolt-port: 8888 可能被占用,修改一下这个端口
# soul/soul-examples/soul-examples-sofa/src/main/resources/application.yml
com:
alipay:
sofa:
rpc:
registry-address: zookeeper://127.0.0.1:2181
bolt-port: 8888 # bolt 协议端口
- 错误日志:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-01-18 14:47:27.139 ERROR 11863 --- [ main] o.s.boot.SpringApplication : Application run failed
com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException: Failed to start bolt server, see more detail from bolt log.
at com.alipay.sofa.rpc.server.bolt.BoltServer.start(BoltServer.java:121) ~[sofa-rpc-all-5.5.7.jar:5.5.7]
at com.alipay.sofa.rpc.boot.container.ServerConfigContainer.startServers(ServerConfigContainer.java:87) ~[rpc-sofa-boot-core-6.0.4.jar:6.0.4]
at com.alipay.sofa.rpc.boot.context.SofaBootRpcStartListener.onApplicationEvent(SofaBootRpcStartListener.java:73) ~[rpc-sofa-boot-core-6.0.4.jar:6.0.4]
at com.alipay.sofa.rpc.boot.context.SofaBootRpcStartListener.onApplicationEvent(SofaBootRpcStartListener.java:41) ~[rpc-sofa-boot-core-6.0.4.jar:6.0.4]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
......
二、通过sofa来看一下soul网关元数据同步原理
soul-bootstrap 加入了 soul-spring-boot-starter-plugin-sofa 依赖,来看一下这部分源码
1、 soul-spring-boot-starter-plugin-sofa
soul-spring-boot-starter-plugin-sofa/src/main/resources/META-INF/spring.factories
// 自动注入 SofaPluginConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.dromara.soul.spring.boot.starter.plugin.sofa.SofaPluginConfiguration
SofaPluginConfiguration 向容器中注入 MetaDataSubscriber bean对象
/**
* Sofa meta data subscriber meta data subscriber.
*
* @return the meta data subscriber
*/
@Bean
public MetaDataSubscriber sofaMetaDataSubscriber() {
return new SofaMetaDataSubscriber();
}
2、MetaDataSubscriber 负责订阅 soul-admin 发布的元数据更新
将订阅的消息更新到 META_DATA,这里看到的只是订阅的具体实现,MetaDataSubscriber 又是如何被调用的?
/**
* The sofa metadata subscribe.
* @author tydhot
*/
public class SofaMetaDataSubscriber implements MetaDataSubscriber {
private static final ConcurrentMap<String, MetaData> META_DATA = Maps.newConcurrentMap();
@Override
public void onSubscribe(final MetaData metaData) {
if (RpcTypeEnum.SOFA.getName().equals(metaData.getRpcType())) {
MetaData exist = META_DATA.get(metaData.getPath());
if (Objects.isNull(exist) || Objects.isNull(ApplicationConfigCache.getInstance().get(exist.getPath()).refer())) {
// The first initialization
ApplicationConfigCache.getInstance().initRef(metaData);
} else {
if (!exist.getServiceName().equals(metaData.getServiceName()) || !exist.getRpcExt().equals(metaData.getRpcExt())) {
// update
ApplicationConfigCache.getInstance().build(metaData);
}
}
META_DATA.put(metaData.getPath(), metaData);
}
}
}
3、在 SofaMetaDataSubscriber -> onSubscribe 打上断点,可以看到方法调用栈,中的
SoulWebsocketClient-> onMessage 方法
4、SoulWebsocketClient 类属于 soul-sync-data-websocket 模块
SoulWebsocketClient 继承了 WebSocketClient 负责监听soul-admin WebSocket 发布的元数据更新通知
/**
* The type Soul websocket client.
*/
@Slf4j
public final class SoulWebsocketClient extends WebSocketClient {
......
@Override
public void onMessage(final String result) {
handleResult(result);
}
@SuppressWarnings("ALL")
private void handleResult(final String result) {
WebsocketData websocketData = GsonUtils.getInstance().fromJson(result, WebsocketData.class);
ConfigGroupEnum groupEnum = ConfigGroupEnum.acquireByName(websocketData.getGroupType());
String eventType = websocketData.getEventType();
String json = GsonUtils.getInstance().toJson(websocketData.getData());
websocketDataHandler.executor(groupEnum, json, eventType);
}
}
5、WebsocketDataHandler 中实例化并加载了所有的订阅者,其中包含 MetaDataSubscriber
/**
* The type Websocket cache handler.
* @author xiaoyu(Myth)
*/
public class WebsocketDataHandler {
private static final EnumMap<ConfigGroupEnum, DataHandler> ENUM_MAP = new EnumMap<>(ConfigGroupEnum.class);
/**
* Instantiates a new Websocket data handler.
* @param pluginDataSubscriber the plugin data subscriber
* @param metaDataSubscribers the meta data subscribers
* @param authDataSubscribers the auth data subscribers
*/
public WebsocketDataHandler(final PluginDataSubscriber pluginDataSubscriber,
final List<MetaDataSubscriber> metaDataSubscribers,
final List<AuthDataSubscriber> authDataSubscribers) {
ENUM_MAP.put(ConfigGroupEnum.PLUGIN, new PluginDataHandler(pluginDataSubscriber));
ENUM_MAP.put(ConfigGroupEnum.SELECTOR, new SelectorDataHandler(pluginDataSubscriber));
ENUM_MAP.put(ConfigGroupEnum.RULE, new RuleDataHandler(pluginDataSubscriber));
ENUM_MAP.put(ConfigGroupEnum.APP_AUTH, new AuthDataHandler(authDataSubscribers));
ENUM_MAP.put(ConfigGroupEnum.META_DATA, new MetaDataHandler(metaDataSubscribers));
}
/**
* Executor.
* @param type the type
* @param json the json
* @param eventType the event type
*/
public void executor(final ConfigGroupEnum type, final String json, final String eventType) {
ENUM_MAP.get(type).handle(json, eventType);
}
}
6、MetaDataHandler 中通过遍历的方式通知所有的订阅者更新元数据,至此我们看清楚了 sofa元数据同步的整个流程
public class MetaDataHandler extends AbstractDataHandler<MetaData> {
private final List<MetaDataSubscriber> metaDataSubscribers;
@Override
public List<MetaData> convert(final String json) {
return GsonUtils.getInstance().fromList(json, MetaData.class);
}
@Override
protected void doRefresh(final List<MetaData> dataList) {
metaDataSubscribers.forEach(MetaDataSubscriber::refresh);
dataList.forEach(metaData -> metaDataSubscribers.forEach(metaDataSubscriber -> metaDataSubscriber.onSubscribe(metaData)));
}
@Override
protected void doUpdate(final List<MetaData> dataList) {
dataList.forEach(metaData -> metaDataSubscribers.forEach(metaDataSubscriber -> metaDataSubscriber.onSubscribe(metaData)));
}
@Override
protected void doDelete(final List<MetaData> dataList) {
dataList.forEach(metaData -> metaDataSubscribers.forEach(metaDataSubscriber -> metaDataSubscriber.unSubscribe(metaData)));
}
}
7、sofa元数据同步原理思维导图
三、总结:
通过sofa元数据加载的过程,元数据同步是通过websocket来实现,这只是soul网关元数据同步的一种,其他还包括http,zookeeper。后续对其他元数据同步方式进行学习。