jck28 - 小柒 - 接口自动化 duubo协议接口测试

一,dubbo协议的接口测试

1,dubbo简介

2,dubbo系统框架

  • 组成:远程服务运行容器-Container,远程服务提供方-Provider、注册中心-Register、远程服务调用者-Consumer、监控中心-Monitor


3,dubbo支持协议

  • dubbo3 triple
  • dubbo2 协议
  • rest 协议
  • http 协议
  • hessian 协议
  • redis 协议
  • thrift 协议
  • gRPC 协议
  • memcached 协议
  • rmi 协议
  • webservice 协议

4,dubbo+zk的注册中心流程

5,dubbo配置结构 - xml

5.1 provider:

   *  声明dubbo服务提供者的名称:保证唯一性:  <dubbo:application name="xx-provider" />
   *  服务注册地址: <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
   *  设置dubbo使用的协议名称和端口: <dubbo:protcol name="dubbo" prot="20880" />
   *  暴露服务接口,引用实现类 : <dubbo:service interface="com.xx.service" ref="xxImpl"/>
   *  加载业务接口的实现类到spring容器中 :<bean id="xxImpl" class="com.xx.serviceImpl" />

5.2 consumer:

<dubbo:application name="xx-consumer"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference id="xx" check="false" interface="com.xx.service"/>

5.3 xml配置示例:

image

5.4 xml配置常用属性:

5.5 在不修改代码或xml配置的情况下,自定义provider和consumer的group,timeout等参数

(1)调用接口修改(-Ddubbo.reference.id.ppp=xxx)
* id为接口全名
* ppp为属性
* xxx为要修改的属性值

  • 示例:dsp服务调用recall服务的lp分组:
    -Ddubbo.reference.com.heytap.ad.show.recall.api.IRecallServiceV2.group=lp.7.irg
    -Ddubbo.reference.com.heytap.ad.show.recall.api.IRecallServiceV2.timeout=5000

(2)服务本身修改(-Ddubbo.service.id.ServiceBean:id:version:group:ppp=xxx)
* id、ppp、xxx同上
* version为实际版本号
* group为实际分组值

  • 示例:recall服务配置lp分组供dsp调用
    -Ddubbo.service.com.heytap.ad.show.recall.api.IRecallServiceV2.ServiceBean:com.heytap.ad.show.recall.api.IRecallServiceV2:2.0.0:7.irg.group=lp.7.irg

6, linux命令下的环境准备和安装

  • 下载统一服务 zookeeper redis并启动

    • zookeeper:cp conf/zoo_sample.cfg conf/zoo.cfg
      bin/zkServer.sh start
    • redis:redis-server
  • dubbo 管理控制台安装

    • 启动命令:
git clone https://github.com/apache/dubbo-admin.git
cd dubbo-admin
git tag
git checkout 0.3.0
mvn clean package -DskipTests
#vim dubbo-admin-server/src/main/resources/application.properties
mvn --projects dubbo-admin-server spring-boot:run -Dserver.port=8080
#http://127.0.0.1:8080
git clone https://github.com/apache/dubbo.git
cd dubbo
git tag
git checkout dubbo-2.7.4.1
cd dubbo-demo

7,dubbo常用测试方法

7.1, telnet 调用 - 手动调用

(1)telnet连接dubbo服务

  • dubbo开启的telnet服务:telnet localhost 20880
    nc localhost 20880
  • qos服务开启的telnet服务:telnet localhost 22222
    nc localhost 22222

(2)查询dubbo服务接口:

* ls:
    ls: 显示服务列表
    ls -l: 显示服务详细信息列表
    ls XxxService: 显示服务的方法列表
    ls -l XxxService: 显示服务的方法详细信息列表
* cd status pwd
* help

(3) invoke 调用(仅适用于json协议)

调用服务的方法
invoke XxxService.xxxMethod(1234, “abcd”, {“prop” : “value”}):
调用全路径服务的方法
invoke com.xxx.XxxService.XxxService.xxxMethod(1234, “abcd”, {“prop” : “value”})
调用服务的方法(自动查找包含此方法的服务)
invoke xxxMethod(1234, “abcd”, {“prop” : “value”}):
当有参数重载,或者类型转换失败的时候,可以通过增加 class 属性指定需要转换类
invoke xxxMethod({“name”:“zhangsan”,“age”:12,“class”:“org.xxx.Person”})
invoke com.xxx.xxxApiService({“3”:0.123, “class”:“java.util.HashMap”})

7.2, rpc 调用 - 通过代码实现调用接口

(1) 导入依赖

 <!-- 添加spring依赖-->
         <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.9.RELEASE</version>
         </dependency>
        <!-- 添加dubbo依赖-->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.8</version>
        </dependency>
        <!-- 添加接口工程依赖-->
        <dependency>
            <groupId>com.ads.test</groupId>
            <artifactId>demo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

(2) 配置consumer
image

(3) dubbo2 接口:以 consumer 的角色去调用

public class DubboTest {
    static DemoService demoService;

    @BeforeAll
    static void beforeAll() {
        //上下文的初始化
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml");
        context.start();
        demoService = context.getBean("demoService", DemoService.class);
    }

    @Test
    void sayHello() {
        String res;
        res = demoService.sayHello("seveniruby");
        assertThat(res, startsWith("Hello seveniruby"));
        res = demoService.sayHello("ceshiren.com");
        assertThat(res, startsWith("Hello ceshiren.com"));
    }
}

(4) dubbo3 接口:

  • dubbo3 的主推协议 triple
    image

  • dubbo3 的使用

    • 定义 pb 数据格式
    • 生成 dubbo3 stub
    • 引入 provider 并编写实现
    • 部署启动 provider 并注册到 registry
    • 通过 consumer 调用
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml");
        context.start();
        DemoService demoService = context.getBean("demoService", DemoService.class);

  HelloRequest request = HelloRequest.newBuilder().setName("Hello").build();
        HelloReply reply = demoService.sayHello(request);
        System.out.println("result: " + reply.getMessage());
        System.in.read();

7.3, 泛化调用

(1)泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。 Dubbo Admin 就是使用此方式

(2)代码示例(仅了解)

// 引用远程服务 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
// 弱类型接口名
reference.setInterface("com.xxx.XxxService");
reference.setVersion("1.0.0");
// 声明为泛化接口
reference.setGeneric(true);
// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
GenericService genericService = reference.get();
// 基本类型以及Date,List,Map等不需要转换,直接调用
Object result = genericService.$invoke("sayHello", new String[] {"java.lang.String"}, new Object[] {"world"});
// 用Map表示POJO参数,如果返回值为POJO也将自动转成Map
Map<String, Object> person = new HashMap<String, Object>();
person.put("name", "xxx");
person.put("password", "yyy");
// 如果返回POJO将自动转成Map
Object result = genericService.$invoke("findPerson", new String[]
{"com.xxx.Person"}, new Object[]{person});

(3)json 泛化调用 2.7.12 版本之后支持

 // 引用远程服务
    ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
    // 弱类型接口名
    reference.setInterface("com.xxx.api.service.TestService");
    reference.setGroup("dev");
    reference.setVersion("1.0");
    reference.setRetries(0);
    // RpcContext中设置generic=gson
    RpcContext.getContext().setAttachment("generic","gson");
    // 声明为泛化接口
    reference.setGeneric(true);
    reference.setCheck(false);
    GenericService genericService = ReferenceConfigCache.getCache().get(reference);
    // 传递参数对象的json字符串进行一次调用
    Object res = genericService.$invoke("setUser", new String[]{"com.xxx.api.service.User"}, new Object[]{"{'name':'Tom','age':24}"});
    System.out.println("result[setUser]:"+res); // 响应结果:result[setUser]:{name=Tom, class=com.xxx.api.service.User, age=24}

(4) pb 协议的泛化调用

ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
// 弱类型接口名
reference.setInterface(GenericService.class.getName());
reference.setInterface("com.xxx.XxxService");
// 声明为Protobuf-json
reference.setGeneric(Constants.GENERIC_SERIALIZATION_PROTOBUF);

GenericService genericService = reference.get();
Map<String, Object> person = new HashMap<String, Object>();
person.put("fixed64", "0");
person.put("int64", "0");
// 参考google官方的protobuf 3 的语法,服务的每个方法中只传输一个POJO对象
// protobuf的泛化调用只允许传递一个类型为String的json对象来代表请求参数
String requestString = new Gson().toJson(person);
// 返回对象是GoolgeProtobuf响应对象的json字符串。
Object result = genericService.$invoke("sayHello", new String[] {
    "com.xxx.XxxService.GooglePbBasic$CDubboGooglePBRequestType"},
    new Object[] {requestString});