目标
-
基于Sofa-Rpc协议的Demo演示
- 引入网关(bootstarp)对sofa支持的插件
- 使用XML方式引入实际业务接口
- Publish service on server
- 被代理业务增加yml配置
- 配置接口注册admin地址信息
- 启动真实业务服务
-
soul-spring-boot-starter-client-sofa注入解析
- sofaConfig读取soul.sofa.xx配置信息
- SofaServiceBeanPostProcessor类注入Bean
- BeanPostProcessor执行
- admin页面展示已经注册的接口
演示和总结
Sofa-Rpc介绍
基于Sofa-Rpc协议的Demo演示
引入网关(bootstarp)对sofa支持的插件
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-rpc-all</artifactId>
<version>5.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-sofa</artifactId>
<version>2.2.1</version>
</dependency>
其中主要的依赖有sofa-rpc-all和封装的soul-spring-boot-starter-plugin-sofa
使用xml方式引入业务接口
<sofa:service ref="sofaTestService" interface="org.dromara.soul.examples.dubbo.api.service.DubboTestService"> <sofa:binding.bolt/> </sofa:service> @ImportResource({ "classpath*:invoke-server-example.xml"})
使用注解@ImportResource() 自动注入
Publish service on server
Configure the followings in the xml file. When the Spring context is refreshed, SOFABoot registers the service implementation on the server, communicates with the client by bolt protocol, and publishes metadata such as address to registry center (local file is used as registry center by default).
上文从Sofa-rpc 官网Getting started 摘录,当被代理服务Bean注入完Spring Context刷新,SOFABoot 就开始将需要被代理的接口注入到Sofa server
被代理业务增加yml配置
- 本实例sofa采用zookeeper作为注册中心,所以本地要启动一个zk,这里使用了之前dubbo实例中的zk,同时配置sofa配置如下:
com:
alipay:
sofa:
rpc: registry-address: zookeeper://127.0.0.1:2181
bolt-port: 8888
Bolt protocol port 是8888
配置接口注册admin地址信息
soul:
sofa:
adminUrl: http://localhost:9095
contextPath: /sofa
appName: sofa
启动真实业务服务
说明Sofa客户端启动成功
从服务启动日志中可以看出 Sofa 与 soul-sofa-client 各个服务的配置先后顺序
Soul-Spring-boot-starter-client-sofa 注入解析
sofaConfig 读取soul.sofa.xx 配置信息
@Bean
@ConfigurationProperties(prefix = "soul.sofa")
public SofaConfig sofaConfig() {
return new SofaConfig();
}
SofaServiceBeanPostProcessor 类注入Bean
public SofaServiceBeanPostProcessor(final SofaConfig sofaConfig) {
String contextPath = sofaConfig.getContextPath();
String adminUrl = sofaConfig.getAdminUrl();
if (contextPath == null || "".equals(contextPath)
|| adminUrl == null || "".equals(adminUrl)) {
throw new RuntimeException("sofa client must config the contextPath, adminUrl");
}
this.sofaConfig = sofaConfig;
url = sofaConfig.getAdminUrl() + "/soul-client/sofa-register";
executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
获取注册admin的sofa相关参数和创建执行注册的线程池
BeanPostProcessor执行
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
if (bean instanceof ServiceFactoryBean) {
executorService.execute(() -> handler((ServiceFactoryBean) bean));
}
return bean;
}
private void handler(final ServiceFactoryBean serviceBean) {
Class<?> clazz;
try {
clazz = ((Service) Objects.requireNonNull(serviceBean.getObject())).getTarget().getClass();
} catch (Exception e) {
log.error("failed to get sofa target class");
return;
}
if (ClassUtils.isCglibProxyClass(clazz)) {
String superClassName = clazz.getGenericSuperclass().getTypeName();
try {
clazz = Class.forName(superClassName);
} catch (ClassNotFoundException e) {
log.error(String.format("class not found: %s", superClassName));
return;
}
}
final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(clazz);
for (Method method : methods) {
SoulSofaClient soulSofaClient = method.getAnnotation(SoulSofaClient.class);
if (Objects.nonNull(soulSofaClient)) {
RegisterUtils.doRegister(buildJsonParams(serviceBean, soulSofaClient, method), url, RpcTypeEnum.SOFA);
}
}
}
主要是使用@SoulSofaClient注解配合反射拿到需要代理的接口
admin 页面展示已经注册的接口
到这里前期初始化工作完成,下面看下调用演示
演示与总结
前面几篇最后都没有总结,今天到此我们已经演示了SpringMvc/SpringCloud,Dubbo,Sofa不同协议的代理方式,总结一下,soul的设计思路:
- 不同协议封装成独立的客户端包,至于使用的协议规范那一套全部在客户端中封装了,使用者只需要根据对应的附加配置信息即可。
- 为每个客户端创建一个spring boot starter,使用了SpringBoot 自动化配置的原理,读取 META-INF/spring.factories 中的自动化配置类进行向admin注册
- 每个协议的客户端基本实现一样,通过BeanPostProcessor和ApplicationListener<ContextRefreshedEvent>加上自定义注解从而达到接口的注册
Sofa-Rpc介绍
SOFARPC 是蚂蚁金服开源的一款基于 Java 实现的 RPC 服务框架,为应用之间提供远程服务调用能力,具有高可伸缩性,高容错性,目前蚂蚁金服所有的业务的相互间的 RPC 调用都是采用 SOFARPC。SOFARPC 为用户提供了负载均衡,流量转发,链路追踪,链路数据透传,故障剔除等功能。
SOFARPC 还支持不同的协议,目前包括 bolt,RESTful,dubbo,H2C 协议进行通信。其中 bolt 是蚂蚁金融服务集团开放的基于 Netty 开发的网络通信框架。
基本原理
当一个 SOFARPC 的应用启动的时候,如果发现当前应用需要发布 RPC 服务的话,那么 SOFARPC 会将这些服务注册到服务注册中心上。如图中 Service 指向 Registry。
- 当引用这个服务的 SOFARPC 应用启动时,会从服务注册中心订阅到相应服务的元数据信息。服务注册中心收到订阅请求后,会将发布方的元数据列表实时推送给服务引用方。如图中 Registry 指向 Reference。
- 当服务引用方拿到地址以后,就可以从中选取地址发起调用了。如图中 Reference 指向 Service。
后面研究单独插件时候好好研究下他的源码