Soul API网关源码解析05

目标

  • 基于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

启动真实业务服务

image.png

说明Sofa客户端启动成功

image.png

从服务启动日志中可以看出 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 页面展示已经注册的接口

image.png

到这里前期初始化工作完成,下面看下调用演示

演示与总结

image.png

前面几篇最后都没有总结,今天到此我们已经演示了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 还支持不同的协议,目前包括 boltRESTfuldubboH2C 协议进行通信。其中 bolt 是蚂蚁金融服务集团开放的基于 Netty 开发的网络通信框架。

基本原理

image.png

当一个 SOFARPC 的应用启动的时候,如果发现当前应用需要发布 RPC 服务的话,那么 SOFARPC 会将这些服务注册到服务注册中心上。如图中 Service 指向 Registry。

  1. 当引用这个服务的 SOFARPC 应用启动时,会从服务注册中心订阅到相应服务的元数据信息。服务注册中心收到订阅请求后,会将发布方的元数据列表实时推送给服务引用方。如图中 Registry 指向 Reference。
  2. 当服务引用方拿到地址以后,就可以从中选取地址发起调用了。如图中 Reference 指向 Service。

后面研究单独插件时候好好研究下他的源码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容