### 带着问题读源码系列之Dubbo插件
像往常一样启动 【soul-admin】 和 【soul-bootstrap】 。
因为dubbo需要依赖zookeeper, 需要需要启动一个监听在 localhost:2181 的zookeeper组件。
然后使用 【soul-examples-apache-dubbo-service】中的 org.dromara.soul.examples.apache.dubbo.service.TestApacheDubboApplication 来注册服务。
这是就可以打开 管理界面 查看dubbo插件的信息。发现已经注册完毕了。
然后使用soul提供的http请求访问
curl http://localhost:9195/dubbo/findAll
{"code":-107,"message":"Can not find selector, please check your configuration!","data":null}%
这里报得是找不到选择器,再查看日志:
java.lang.IllegalStateException: No such application config! Please add <dubbo:application name="..." /> to your spring config.
at com.alibaba.dubbo.config.AbstractInterfaceConfig.checkApplication(AbstractInterfaceConfig.java:145) ~[dubbo-2.6.5.jar:2.6.5]
at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:278) ~[dubbo-2.6.5.jar:2.6.5]
at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163) ~[dubbo-2.6.5.jar:2.6.5]
at org.dromara.soul.plugin.alibaba.dubbo.cache.ApplicationConfigCache.build(ApplicationConfigCache.java:166) ~[classes/:na]
at org.dromara.soul.plugin.alibaba.dubbo.cache.ApplicationConfigCache.initRef(ApplicationConfigCache.java:130) ~[classes/:na]
at org.dromara.soul.plugin.alibaba.dubbo.subscriber.AlibabaDubboMetaDataSubscriber.onSubscribe(AlibabaDubboMetaDataSubscriber.java:43) ~[classes/:na]
at org.dromara.soul.plugin.sync.data.weboscket.handler.MetaDataHandler.lambda$null$0(MetaDataHandler.java:42) ~[classes/:na]
at java.util.ArrayList.forEach(ArrayList.java:1257) ~[na:1.8.0_201]
at org.dromara.soul.plugin.sync.data.weboscket.handler.MetaDataHandler.lambda$doRefresh$1(MetaDataHandler.java:42) ~[classes/:na]
at java.util.ArrayList.forEach(ArrayList.java:1257) ~[na:1.8.0_201]
at org.dromara.soul.plugin.sync.data.weboscket.handler.MetaDataHandler.doRefresh(MetaDataHandler.java:42) ~[classes/:na]
at org.dromara.soul.plugin.sync.data.weboscket.handler.AbstractDataHandler.handle(AbstractDataHandler.java:68) ~[classes/:na]
at org.dromara.soul.plugin.sync.data.weboscket.handler.WebsocketDataHandler.executor(WebsocketDataHandler.java:61) ~[classes/:na]
at org.dromara.soul.plugin.sync.data.weboscket.client.SoulWebsocketClient.handleResult(SoulWebsocketClient.java:87) ~[classes/:na]
at org.dromara.soul.plugin.sync.data.weboscket.client.SoulWebsocketClient.onMessage(SoulWebsocketClient.java:68) ~[classes/:na]
at org.java_websocket.client.WebSocketClient.onWebsocketMessage(WebSocketClient.java:591) [Java-WebSocket-1.5.0.jar:na]
at org.java_websocket.drafts.Draft_6455.processFrameText(Draft_6455.java:885) [Java-WebSocket-1.5.0.jar:na]
at org.java_websocket.drafts.Draft_6455.processFrame(Draft_6455.java:819) [Java-WebSocket-1.5.0.jar:na]
at org.java_websocket.WebSocketImpl.decodeFrames(WebSocketImpl.java:379) [Java-WebSocket-1.5.0.jar:na]
at org.java_websocket.WebSocketImpl.decode(WebSocketImpl.java:216) [Java-WebSocket-1.5.0.jar:na]
at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:508) [Java-WebSocket-1.5.0.jar:na]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]
> 2021-01-16 08:30:17.149 INFO 6397 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 9195
> 2021-01-16 08:30:17.152 INFO 6397 --- [ main] o.d.s.b.SoulBootstrapApplication : Started SoulBootstrapApplication in 3.704 seconds (JVM running for 4.3)
> 2021-01-16 08:30:26.271 INFO 6397 --- [ocket-connect-1] o.d.s.p.s.d.w.WebsocketSyncDataService : websocket reconnect is successful.....
> 2021-01-16 08:30:26.612 ERROR 6397 --- [-work-threads-1] o.d.soul.plugin.base.utils.CheckUtils : can not match selector data: divide
这里日志现实dubbo服务就没有注册上来,说明dubbo插件没有启动成功,通过查看插件管理,发现dubbo插件没有开启,手动开启后。然后调用:
curl http://127.0.0.1:9195/dubbo/findAll
{"code":200,"message":"Access to success!","data":{"name":"hello world Soul Apache, findAll","id":"-721302769"}}%
如此调用成功。
通过example的列子,可以将soul网关dubbo插件的使用分为如下过程:
1. 在提供者处添加依赖
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-client-apache-dubbo</artifactId>
<version>${soul.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-examples-dubbo-api</artifactId>
</dependency>
<!--spring boot的核心启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--aop支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--自动配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- Dubbo dependency -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${apache.dubbo.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<!-- Dubbo Nacos registry dependency -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${apache.dubbo.version}</version>
</dependency>
<!-- Keep latest Nacos client version -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos-client.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2. 添加dubbo配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="test-dubbo-service"/>
<dubbo:registry address="zookeeper://localhost:2181"/>
<dubbo:protocol name="dubbo" port="20888"/>
<dubbo:service timeout="10000" interface="org.dromara.soul.examples.dubbo.api.service.DubboTestService" ref="dubboTestService"/>
<dubbo:service timeout="10000" interface="org.dromara.soul.examples.dubbo.api.service.DubboMultiParamService" ref="dubboMultiParamService"/>
</beans>
3. 在application.yml添加配置
soul:
dubbo:
# soul-admin地址
adminUrl: http://localhost:9095
# 匹配的url前缀
contextPath: /dubbo
appName: dubbo
下面阅读Soul的 DubboPlugin 的代码
public class ApacheDubboPlugin extends AbstractSoulPlugin {
private final ApacheDubboProxyService dubboProxyService;
/**
* Instantiates a new Dubbo plugin.
*
* @param dubboProxyService the dubbo proxy service
*/
public ApacheDubboPlugin(final ApacheDubboProxyService dubboProxyService) {
this.dubboProxyService = dubboProxyService;
}
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
String body = exchange.getAttribute(Constants.DUBBO_PARAMS); // 获取dubbo的请求
SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT); // 获取soul上下文
assert soulContext != null;
MetaData metaData = exchange.getAttribute(Constants.META_DATA); // 获取元数据
if (!checkMetaData(metaData)) {
assert metaData != null;
log.error(" path is :{}, meta data have error.... {}", soulContext.getPath(), metaData.toString());
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
Object error = SoulResultWrap.error(SoulResultEnum.META_DATA_ERROR.getCode(), SoulResultEnum.META_DATA_ERROR.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
if (StringUtils.isNoneBlank(metaData.getParameterTypes()) && StringUtils.isBlank(body)) { // 判断请求合法性
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
Object error = SoulResultWrap.error(SoulResultEnum.DUBBO_HAVE_BODY_PARAM.getCode(), SoulResultEnum.DUBBO_HAVE_BODY_PARAM.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
final Mono<Object> result = dubboProxyService.genericInvoker(body, metaData, exchange);
return result.then(chain.execute(exchange));
}
/**
* acquire plugin name.
*
* @return plugin name.
*/
@Override
public String named() {
return PluginEnum.DUBBO.getName();
}
/**
* plugin is execute.
*
* @param exchange the current server exchange
* @return default false.
*/
@Override
public Boolean skip(final ServerWebExchange exchange) {
final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
assert soulContext != null;
return !Objects.equals(soulContext.getRpcType(), RpcTypeEnum.DUBBO.getName());
}
@Override
public int getOrder() {
return PluginEnum.DUBBO.getCode();
}
private boolean checkMetaData(final MetaData metaData) {
return null != metaData && !StringUtils.isBlank(metaData.getMethodName()) && !StringUtils.isBlank(metaData.getServiceName());
}
}