整合sofa插件,接入网关
一、启动服务
作为RPC框架,sofa和dubbo在插件接入上有着一定的相似性。那么我们还是和前面的案例一样,先启动服务,启动服务的顺序是:
- soul-admin
- soul-bootstrap
- soul-examples-sofa
不过在启动服务前,我们先看看配置文件:
1、soul-examples-sofa pom 依赖
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-client-sofa</artifactId>
<version>${soul.version}</version>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
2、application.yml
server:
port: 28011
address: 0.0.0.0
servlet:
context-path: /
spring:
main:
allow-bean-definition-overriding: true
application:
name: sofa
com:
alipay:
sofa:
rpc:
registry-address: zookeeper://127.0.0.1:2181
bolt-port: 8888
soul:
sofa:
adminUrl: http://localhost:9095
contextPath: /sofa
appName: sofa
3、启动类
@SpringBootApplication
@ImportResource({
"classpath*:invoke-server-example.xml"})
public class TestSofaApplication {
/**
* Main Entrance.
*
* @param args startup arguments
*/
public static void main(final String[] args) {
SpringApplication.run(TestSofaApplication.class, args);
}
}
注意:记得启动 zk、在启动admin后开启sofa插件
二、关于sofa 的元数据同步
1、自动装配
这是源于 Spring Boot 的自动装配原理:
这里我们可以看到这个位置是在我们的sofa-example的pom文件中引用的那个模块。然后我们可以看看SofaPluginConfiguration这个类:
@Configuration
@ConditionalOnClass(SofaPlugin.class)
public class SofaPluginConfiguration {
/**
* Sofa plugin soul plugin.
*
* @param sofaParamResolveService the sofa param resolve service
* @return the soul plugin
*/
@Bean
public SoulPlugin sofaPlugin(final ObjectProvider<SofaParamResolveService> sofaParamResolveService) {
return new SofaPlugin(new SofaProxyService(sofaParamResolveService.getIfAvailable()));
}
/**
* Body param plugin soul plugin.
*
* @return the soul plugin
*/
@Bean
public SoulPlugin sofaBodyParamPlugin() {
return new BodyParamPlugin();
}
/**
* Dubbo response plugin soul plugin.
*
* @return the soul plugin
*/
@Bean
public SoulPlugin sofaResponsePlugin() {
return new SofaResponsePlugin();
}
/**
* Sofa plugin data handler plugin data handler.
*
* @return the plugin data handler
*/
@Bean
public PluginDataHandler sofaPluginDataHandler() {
return new SofaPluginDataHandler();
}
/**
* Sofa meta data subscriber meta data subscriber.
*
* @return the meta data subscriber
*/
@Bean
public MetaDataSubscriber sofaMetaDataSubscriber() {
return new SofaMetaDataSubscriber();
}
}
从上面代码中,我们可以看到SofaPluginConfiguration会根据SofaPlugin这个条件,来装配我们的Bean,在这里面会装配SofaPlugin、BodyParamPlugin、PluginDataHandler、MetaDataSubscriber。
2、元数据订阅调用
这里面的MetaDataSubscriber是负责订阅admin发布的元数据的更新的。那我们可以看看订阅和取消订阅的调用代码:
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);
}
}
@Override
public void unSubscribe(final MetaData metaData) {
if (RpcTypeEnum.SOFA.getName().equals(metaData.getRpcType())) {
ApplicationConfigCache.getInstance().invalidate(metaData.getPath());
META_DATA.remove(metaData.getPath());
}
}
}
感兴趣的童鞋可以自己去debug看看代码的调用链路。不过和前面几个示例是类似的。这里笔者只做简单的代码展示分析。而订阅的调用的位置是在MetaDataHandler类中:
*/
@RequiredArgsConstructor
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)));
}
}
从上面代码中,可以看到订阅的调用时机是在doRefresh、doUpdate、doDelete这几个方法里的。
但是我们还是要关注MetaDataHandler是如何生成的:
3、处理相关类的装配过程
接着我们来看看WebsocketDataHandler类的生成时机:
接下来就是SoulWebsocketClient类的生成了:
最后看到的是SoulWebsocketClient的装配位置了:
@Configuration
@ConditionalOnClass(WebsocketSyncDataService.class)
@ConditionalOnProperty(prefix = "soul.sync.websocket", name = "urls")
@Slf4j
public class WebsocketSyncDataConfiguration {
/**
* Websocket sync data service.
*
* @param websocketConfig the websocket config
* @param pluginSubscriber the plugin subscriber
* @param metaSubscribers the meta subscribers
* @param authSubscribers the auth subscribers
* @return the sync data service
*/
@Bean
public SyncDataService websocketSyncDataService(final ObjectProvider<WebsocketConfig> websocketConfig, final ObjectProvider<PluginDataSubscriber> pluginSubscriber,
final ObjectProvider<List<MetaDataSubscriber>> metaSubscribers, final ObjectProvider<List<AuthDataSubscriber>> authSubscribers) {
log.info("you use websocket sync soul data.......");
return new WebsocketSyncDataService(websocketConfig.getIfAvailable(WebsocketConfig::new), pluginSubscriber.getIfAvailable(),
metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
}
/**
* Config websocket config.
*
* @return the websocket config
*/
@Bean
@ConfigurationProperties(prefix = "soul.sync.websocket")
public WebsocketConfig websocketConfig() {
return new WebsocketConfig();
}
}
总结
由于时间原因只能做了一个简单的分析,其中的很多细节还没有涉及到,当然也有一些处理的细节和前面的是一样的,譬如bean的前置处理等等。
本篇只是简单的介绍了启动服务的过程及配置文件的注意点,最后就是关于sofa元数据这块的相关信息,有自动装配、订阅的调用、以及元数据处理类的装配过程。
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/1287.html