干貨 | Dubbo 接口測(cè)試原理及多種方法實(shí)踐總結(jié)

在這里插入圖片描述

本文為霍格沃茲測(cè)試學(xué)院優(yōu)秀學(xué)員學(xué)習(xí)筆記硼一,進(jìn)階學(xué)習(xí)文末加群。

更多技術(shù)文章分享及測(cè)試資料點(diǎn)此獲取

1梦抢、什么是 Dubbo般贼?

Dubbo 最開(kāi)始是應(yīng)用于淘寶網(wǎng),由阿里巴巴開(kāi)源的一款優(yōu)秀的高性能服務(wù)框架奥吩,由 Java 開(kāi)發(fā)哼蛆,后來(lái)貢獻(xiàn)給了 Apache 開(kāi)源基金會(huì)組織。

下面以官網(wǎng)的一個(gè)說(shuō)明來(lái)了解一下架構(gòu)的演變過(guò)程霞赫,從而了解 Dubbo 的誕生原因:


image

單一應(yīng)用架構(gòu)

當(dāng)網(wǎng)站流量很小時(shí)腮介,只需一個(gè)應(yīng)用,將所有功能都部署在一起端衰,以減少部署節(jié)點(diǎn)和成本叠洗。此時(shí)甘改,用于簡(jiǎn)化增刪改查工作量的數(shù)據(jù)訪(fǎng)問(wèn)框架(ORM)是關(guān)鍵。

垂直應(yīng)用架構(gòu)

當(dāng)訪(fǎng)問(wèn)量逐漸增大灭抑,單一應(yīng)用增加機(jī)器帶來(lái)的加速度越來(lái)越小十艾,提升效率的方法之一是將應(yīng)用拆成互不相干的幾個(gè)應(yīng)用,以提升效率名挥。此時(shí)疟羹,用于加速前端頁(yè)面開(kāi)發(fā)的 Web 框架(MVC)是關(guān)鍵。

分布式服務(wù)架構(gòu)

當(dāng)垂直應(yīng)用越來(lái)越多禀倔,應(yīng)用之間交互不可避免榄融,將核心業(yè)務(wù)抽取出來(lái),作為獨(dú)立的服務(wù)救湖,逐漸形成穩(wěn)定的服務(wù)中心愧杯,使前端應(yīng)用能更快速的響應(yīng)多變的市場(chǎng)需求。此時(shí)鞋既,用于提高業(yè)務(wù)復(fù)用及整合的分布式服務(wù)框架(RPC)是關(guān)鍵力九。

流動(dòng)計(jì)算架構(gòu)

當(dāng)服務(wù)越來(lái)越多,容量的評(píng)估邑闺,小服務(wù)資源的浪費(fèi)等問(wèn)題逐漸顯現(xiàn)跌前,此時(shí)需增加一個(gè)調(diào)度中心基于訪(fǎng)問(wèn)壓力實(shí)時(shí)管理集群容量,提高集群利用率陡舅。此時(shí)抵乓,用于提高機(jī)器利用率的資源調(diào)度和治理中心(SOA)是關(guān)鍵。

2靶衍、Dubbo 架構(gòu)簡(jiǎn)介

image

image

Dubbo 比較有特點(diǎn)的地方就是這個(gè)注冊(cè)中心灾炭,平常我們測(cè)試較多的 HTTP 接口,直接請(qǐng)求接口颅眶,調(diào)用后端服務(wù)即可蜈出;而 Dubbo是要先走注冊(cè)中心獲取服務(wù)的位置,下面來(lái)舉個(gè)現(xiàn)實(shí)生活中的例子來(lái)說(shuō)明涛酗。

現(xiàn)實(shí)舉例

好比大家平常約朋友一起出去吃飯铡原,聽(tīng)說(shuō)川菜館“贈(zèng)李白”不錯(cuò),然后需要找這家飯店在哪(用小藍(lán)或小黃App)商叹,知道了具體的地址才出發(fā)眷蜈,至于是走路,打車(chē)還是騎車(chē)沈自,就隨意了酌儒。

這里 App 就相當(dāng)于注冊(cè)中心(Registry),我們這群吃貨就是消費(fèi)者(Consumer)枯途,商家屬于生產(chǎn)者(Provider)忌怎。商家把自己的信息注冊(cè)在 App 上籍滴,消費(fèi)者根據(jù) App 查詢(xún)到商家的信息,再根據(jù)信息找到商家進(jìn)行消費(fèi)榴啸。

2.1孽惰、Zookeeper 簡(jiǎn)介

之前經(jīng)常有小伙伴問(wèn)我 zk 干啥的?怎么用鸥印?下面就來(lái)簡(jiǎn)單了解一哈:

ZK勋功,全稱(chēng)就是zookeeper,是 Apache 軟件基金會(huì)的一個(gè)軟件項(xiàng)目库说,它為大型分布式計(jì)算提供開(kāi)源的分布式配置服務(wù)狂鞋、同步服務(wù)和命名注冊(cè)。

下面的圖示也可以清晰的說(shuō)明zk的部署和工作的一些方式(具體的技術(shù)細(xì)節(jié)需要的話(huà)可以針對(duì)zk專(zhuān)門(mén)搜索學(xué)習(xí)):


image

Leader:集群工作的核心潜的,事務(wù)請(qǐng)求的唯一調(diào)度和處理者骚揍,保證事務(wù)處理的順序性。對(duì)于有寫(xiě)操作的請(qǐng)求啰挪,需統(tǒng)一轉(zhuǎn)發(fā)給Leader處理信不。Leader需決定編號(hào)執(zhí)行操作。

Follower:處理客戶(hù)端非事務(wù)請(qǐng)求亡呵,轉(zhuǎn)發(fā)事務(wù)請(qǐng)求轉(zhuǎn)發(fā)給Leader抽活,參與Leader選舉。

Observer觀(guān)察者:進(jìn)行非事務(wù)請(qǐng)求的獨(dú)立處理,對(duì)于事務(wù)請(qǐng)求,則轉(zhuǎn)發(fā)給Leader服務(wù)器進(jìn)行處理.不參與投票锰什。

3酌壕、什么是 Dubbo 接口?

所謂的 Dubbo 接口歇由,其實(shí)就是一個(gè)個(gè) Dubbo 服務(wù)中的方法,而測(cè)試 Dubbo 接口就相當(dāng)于我們測(cè)試人員充當(dāng)消費(fèi)者或者創(chuàng)造消費(fèi)者去"消費(fèi)"這個(gè)方法果港。

具體的方式有很多沦泌,代碼、工具辛掠、命令皆可谢谦,在接下來(lái)的內(nèi)容中來(lái)一一演示。

4萝衩、Dubbo 接口測(cè)試(創(chuàng)造消費(fèi)者)

以下我將以本地的一個(gè)簡(jiǎn)單的 Dubbo 服務(wù) demo 為例回挽,演示 Dubbo 測(cè)試的各種方法。

interface只有兩個(gè)猩谊,分別是OrderService和UserService


image

OrderService:

package com.qinzhen.testmall.service;

import com.qinzhen.testmall.bean.UserAddress;
import java.util.List;

public interface OrderService {

    /**
     * 初始化訂單
     * @param userID
     */
    public List<UserAddress> initOrder(String userID);
}

UserService:

package com.qinzhen.testmall.service;

import com.qinzhen.testmall.bean.UserAddress;
import java.util.List;

/**
 * 用戶(hù)服務(wù)
 */
public interface UserService {


    /**
     * 按照userId返回所有的收獲地址
     * @param userId
     * @return
     */
    public List<UserAddress> getUserAddressList(String userId);


    /**
     * 返回所有的收獲地址
     * @param 
     * @return
     */
    public List<UserAddress> getUserAddressList();
}

JavaBean 對(duì)象 UserAddress 如下:

package com.qinzhen.testmall.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;

@AllArgsConstructor
@Data
public class UserAddress implements Serializable {

    private Integer id;
    private String userAddress; //用戶(hù)地址
    private String userId; //用戶(hù)ID
    private String consignee; //收貨人
    private String phoneNum; //電話(huà)號(hào)碼
    private String isDefault; //是否為默認(rèn)地址 Y-是  N-否

    public UserAddress(){

    }
}

創(chuàng)建一個(gè)provider來(lái)實(shí)現(xiàn)UserService的Interface:


image

實(shí)現(xiàn)方法中千劈,根據(jù) id 返回對(duì)應(yīng)的用戶(hù)地址信息即可:

package com.qinzhen.testmall.bootuserserviceprovider.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.qinzhen.testmall.bean.UserAddress;
import com.qinzhen.testmall.service.UserService;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Component
@Service  //暴露服務(wù)
public class UserServiceImpl implements UserService {

    private UserAddress userAddress1 = new UserAddress(1, "杭州市西湖區(qū)XX公司", "1", "qz", "12345678", "Y");
    private UserAddress userAddress2 = new UserAddress(2, "杭州市西湖區(qū)花園", "2", "qz", "12345678", "N");

    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        if (userId.equals("1")){
            return Collections.singletonList(userAddress1);
        }
        else if (userId.equals("2")){
            return Collections.singletonList(userAddress2);
        }
        else {
            return Arrays.asList(userAddress1, userAddress2);
        }
    }

    @Override
    public List<UserAddress> getUserAddressList(){
        return Arrays.asList(userAddress1, userAddress2);
    }
}

4.1 Java consumer 代碼

下面我們編寫(xiě)consumer代碼,讓服務(wù)消費(fèi)者去注冊(cè)中心訂閱服務(wù)提供者的服務(wù)地址牌捷,以RPC方式墙牌,獲取遠(yuǎn)程服務(wù)代理涡驮,從而執(zhí)行遠(yuǎn)程方法,代碼也很簡(jiǎn)單喜滨,如下:

代碼結(jié)構(gòu)

image

實(shí)現(xiàn)場(chǎng)景就是實(shí)現(xiàn)OrderService中的initOrder()方法捉捅,初始化訂單,初始化中直接調(diào)用userService的getUserAddressLis(java.lang.String)方法,具體代碼如下:

package com.qinzhen.testmall.service.impl;

import com.qinzhen.testmall.bean.UserAddress;
import com.qinzhen.testmall.service.OrderService;
import com.qinzhen.testmall.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

/**
 * 1虽风、講服務(wù)提供者注冊(cè)到注冊(cè)中心(暴露服務(wù))
 *          1)導(dǎo)入dubbo依賴(lài):操作zookeeper的客戶(hù)端(curator)
 * 2棒口、讓服務(wù)消費(fèi)者去注冊(cè)中心訂閱服務(wù)提供者的服務(wù)地址
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    UserService userService;

    public List<UserAddress> initOrder(String userId) {
        //1.查詢(xún)用戶(hù)的收貨地址
        System.out.println("用戶(hù)ID為:" + userId);
        List<UserAddress> userAddressList = userService.getUserAddressList(userId);
        return userAddressList;
    }
}

consumer MainApplication

package com.qinzhen.testmall;

import com.qinzhen.testmall.bean.UserAddress;
import com.qinzhen.testmall.service.OrderService;
import com.qinzhen.testmall.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;


/**
 * 1、將服務(wù)提供者注冊(cè)到注冊(cè)中心(暴露服務(wù))
 *          1)導(dǎo)入dubbo依賴(lài):操作zookeeper的客戶(hù)端(curator)
 * 2辜膝、讓服務(wù)消費(fèi)者去注冊(cè)中心訂閱服務(wù)提供者的服務(wù)地址
 */
@Service
public class MainApplication {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"consumer.xml"});
        context.start();
        OrderService orderService = context.getBean(OrderService.class); // 獲取遠(yuǎn)程服務(wù)代理
        List<UserAddress> userAddresses = orderService.initOrder("3");// 執(zhí)行遠(yuǎn)程方法
        System.out.println(userAddresses);
        System.out.println("調(diào)用完成无牵。。内舟。");
        System.in.read();
    }
}

consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:context="http://www.springframework.org/schema/context"
       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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.qinzhen.testmall.service.impl"></context:component-scan>

    <dubbo:application name="order-service-comsumer"></dubbo:application>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>

    <!--聲明需要遠(yuǎn)程調(diào)用遠(yuǎn)程服務(wù)的接口合敦,生成遠(yuǎn)程服務(wù)代理-->
    <dubbo:reference interface="com.qinzhen.testmall.service.UserService" id="userService"></dubbo:reference>

</beans>

實(shí)例演示
首先確保provider已啟動(dòng):

image

運(yùn)行consumer,可以看到成功調(diào)用到dubbo方法,獲取地址列表信息:


image

4.2 telnet+invoke

我們使用 telnet 命令可以直接訪(fǎng)問(wèn)對(duì)應(yīng)的服務(wù)验游,但是前提是你需要知道服務(wù)對(duì)應(yīng)的ip+端口充岛。

如下配置文件,我們可以知道服務(wù)暴露在本地的20880端口

dubbo.application.name=boot-user-service-provider
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

使用 telnet 命令進(jìn)行訪(fǎng)問(wèn)耕蝉,如下出現(xiàn) Dubbo 字樣時(shí)說(shuō)明連接成功:

% telnet localhost 20880
Trying ::1...
Connected to localhost.
Escape character is '^]'.

dubbo>

Dubbo 內(nèi)建的 telnet 命令的說(shuō)明和用法如下

  • ls
    • ls: 顯示服務(wù)列表
    • ls -l: 顯示服務(wù)詳細(xì)信息列表
    • ls XxxService: 顯示服務(wù)的方法列表
    • ls -l XxxService: 顯示服務(wù)的方法詳細(xì)信息列表
dubbo>ls
com.qinzhen.testmall.service.UserService

dubbo>ls -l
com.qinzhen.testmall.service.UserService -> dubbo://192.168.2.xxx:20880/com.qinzhen.testmall.service.UserService?anyhost=true&application=boot-user-service-provider&bind.ip=192.168.2.xxx&bind.port=20880&dubbo=2.6.2&generic=false&interface=com.qinzhen.testmall.service.UserService&methods=getUserAddressList&pid=55472&qos.enable=false&side=provider&timestamp=1615088321885

dubbo>dubbo>ls com.qinzhen.testmall.service.UserService
getUserAddressList
getUserAddressList

dubbo>dubbo>ls -l com.qinzhen.testmall.service.UserService
java.util.List getUserAddressList(java.lang.String)
java.util.List getUserAddressList()
  • invoke
    • invoke XxxService.xxxMethod(1234, "abcd", {"prop" : "value"}): 調(diào)用服務(wù)的方法
    • invoke com.xxx.XxxService.XxxService.xxxMethod(1234, "abcd", {"prop" : "value"}): 調(diào)用全路徑服務(wù)的方法
    • invoke xxxMethod(1234, "abcd", {"prop" : "value"}): 調(diào)用服務(wù)的方法(自動(dòng)查找包含此方法的服務(wù))
    • invoke xxxMethod({"name":"zhangsan","age":12,"class":"org.apache.dubbo.qos.legacy.service.Person"}) :當(dāng)有參數(shù)重載崔梗,或者類(lèi)型轉(zhuǎn)換失敗的時(shí)候,可以通過(guò)增加class屬性指定需要轉(zhuǎn)換類(lèi)
    • 當(dāng)參數(shù)為Map<Integer,T>垒在,key的類(lèi)型為Integer時(shí)蒜魄,建議指定類(lèi)型。例如invoke com.xxx.xxxApiService({"3":0.123, "class":"java.util.HashMap"})

然后我們使用invoke 命令對(duì)dubbo方法getUserAddressList()進(jìn)行調(diào)用场躯,如下:

dubbo>invoke getUserAddressList()
[{"consignee":"qz","id":1,"isDefault":"Y","phoneNum":"12345678","userAddress":"杭州市西湖區(qū)xx公司","userId":"1"},{"consignee":"qz","id":2,"isDefault":"N","phoneNum":"12345678","userAddress":"杭州市西湖區(qū)xx花園","userId":"2"}]

dubbo>invoke getUserAddressList("1")
[{"consignee":"qz","id":1,"isDefault":"Y","phoneNum":"12345678","userAddress":"杭州市西湖區(qū)xx公司","userId":"1"}]
elapsed: 14 ms.

學(xué)習(xí)鏈接
其他 Telnet 命令相關(guān)操作谈为,需要可參考 Dubbo 官網(wǎng):

4.3 JMeter

對(duì)于 JMeter 測(cè)試 Dubbo 接口的方法,可參考往期文章:
《基于 Jmeter 完成 Dubbo 接口的測(cè)試》

4.4 Dubbo-admin

對(duì)于 Dubbo-admin 的安裝調(diào)試踢关,可參考文章:
《dubbo-admin+zookeeper 的環(huán)境搭建實(shí)操與 Could not extract archive 報(bào)錯(cuò)踩坑》

4.5 泛化調(diào)用

測(cè)試 Dubbo 服務(wù)的時(shí)候伞鲫,我們需要服務(wù)端的同學(xué)給我們提供 API,沒(méi)有這個(gè) API 我們是測(cè)不了的签舞,而為了解決這個(gè)問(wèn)題秕脓,Dubbo 官方又給我們提供了另外一個(gè)方法,就是泛化調(diào)用儒搭,來(lái)看看官方的解釋?zhuān)?/p>

image

泛化調(diào)用的使用

Dubbo 給我們提供了一個(gè)接口GenericService吠架,這個(gè)接口只有一個(gè)方法,就是$invoke搂鲫,它接受三個(gè)參數(shù)傍药,分別為方法名、方法參數(shù)類(lèi)型數(shù)組和參數(shù)值數(shù)組;
下面我們直接上代碼演示:

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.junit.jupiter.api.Test;

public class TestDemo {

    @Test
    void testDubboGenericService(){
        // 引用遠(yuǎn)程服務(wù)
        // 該實(shí)例很重量怔檩,里面封裝了所有與注冊(cè)中心及服務(wù)提供方連接褪秀,請(qǐng)緩存
        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
        // 弱類(lèi)型接口名
        reference.setApplication(new ApplicationConfig("order-service-consumer"));
        reference.setInterface("com.qinzhen.testmall.service.UserService");
        reference.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));

        // 聲明為泛化接口
        reference.setGeneric(true);

        // 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
        GenericService genericService = reference.get();

        Object result = genericService.$invoke("getUserAddressList", new String[] {"java.lang.String"}, new Object[] {"2"});
        System.out.println(result);

    }
}

運(yùn)行后我們來(lái)看看結(jié)果,咦~也成功訪(fǎng)問(wèn)了:


image

泛化調(diào)用的原理
我們通過(guò) debug 跟入 Dubbo 的源碼中薛训,可以得到如下的調(diào)用鏈:

服務(wù)消費(fèi)端:


在這里插入圖片描述

服務(wù)提供端:


image

從上面的調(diào)用鏈可以知道完成一次泛化調(diào)用媒吗,Dubbo 框架經(jīng)歷了很多過(guò)濾器,我們分別選取兩端鏈路中的最后一步的 Filter 來(lái)簡(jiǎn)單了解一下泛化調(diào)用做了哪些事.

簡(jiǎn)化后的調(diào)用關(guān)系就如下:


image

先來(lái)看consumer端的GenericImplFilter乙埃,大概看下核心的處理步驟:

// 判斷是否為泛化調(diào)用
if (invocation.getMethodName().equals(Constants.$INVOKE)
                && invocation.getArguments() != null
                && invocation.getArguments().length == 3
                && ProtocolUtils.isGeneric(generic)) {
   // 獲取泛化調(diào)用參數(shù)
            Object[] args = (Object[]) invocation.getArguments()[2];
            // 判斷是否為nativejava方式
            if (ProtocolUtils.isJavaGenericSerialization(generic)) {

                for (Object arg : args) {
                    if (!(byte[].class == arg.getClass())) {
                        error(byte[].class.getName(), arg.getClass().getName());
                    }
                }
            // 判斷是否為bean方式
            } else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
                for (Object arg : args) {
                    if (!(arg instanceof JavaBeanDescriptor)) {
                        error(JavaBeanDescriptor.class.getName(), arg.getClass().getName());
                    }
                }
            }
   // 設(shè)置為泛化調(diào)用方式
            ((RpcInvocation) invocation).setAttachment(
                    Constants.GENERIC_KEY, invoker.getUrl().getParameter(Constants.GENERIC_KEY));
        }
        // 發(fā)起遠(yuǎn)程調(diào)用
        return invoker.invoke(invocation);

再來(lái)看provider端的GenericFilter闸英,大概的核心處理步驟如下:

package com.alibaba.dubbo.rpc.filter;

import ...

/**
 * GenericInvokerFilter.
 */
@Activate(group = Constants.PROVIDER, order = -20000)
public class GenericFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
     // 判斷是否為泛化請(qǐng)求
        if (inv.getMethodName().equals(Constants.$INVOKE)
                && inv.getArguments() != null
                && inv.getArguments().length == 3
                && !ProtocolUtils.isGeneric(invoker.getUrl().getParameter(Constants.GENERIC_KEY))) {
            // 獲取參數(shù)名稱(chēng)、參數(shù)類(lèi)型介袜、參數(shù)值
            String name = ((String) inv.getArguments()[0]).trim();
            String[] types = (String[]) inv.getArguments()[1];
            Object[] args = (Object[]) inv.getArguments()[2];
            try {
             // 使用反射獲取調(diào)用方法
                Method method = ReflectUtils.findMethodByMethodSignature(invoker.getInterface(), name, types);
                Class<?>[] params = method.getParameterTypes();
                if (args == null) {
                    args = new Object[params.length];
                }
                // 獲取泛化引用方式使用的泛化類(lèi)型
                String generic = inv.getAttachment(Constants.GENERIC_KEY);
                // 泛化類(lèi)型為空的話(huà)就使用generic=true的方式
                if (StringUtils.isEmpty(generic)
                        || ProtocolUtils.isDefaultGenericSerialization(generic)) {
                    args = PojoUtils.realize(args, params, method.getGenericParameterTypes());
                // 判斷是否為generic=nativejava方式
                } else if (ProtocolUtils.isJavaGenericSerialization(generic)) {
                    for (int i = 0; i < args.length; i++) {
                        if (byte[].class == args[i].getClass()) {
                            try {
                                UnsafeByteArrayInputStream is = new UnsafeByteArrayInputStream((byte[]) args[i]);
                                args[i] = ExtensionLoader.getExtensionLoader(Serialization.class)
                                        .getExtension(Constants.GENERIC_SERIALIZATION_NATIVE_JAVA)
                                        .deserialize(null, is).readObject();
                            } catch (Exception e) {
                                甫何。。遇伞。
                            }
                        } else {
                            辙喂。。鸠珠。
                        }
                    }
                  // 判斷是否為generic=bean方式
                } else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
                    for (int i = 0; i < args.length; i++) {
                        if (args[i] instanceof JavaBeanDescriptor) {
                            args[i] = JavaBeanSerializeUtil.deserialize((JavaBeanDescriptor) args[i]);
                        } else {
                            巍耗。。渐排。
                        }
                    }
                }
                // 傳遞請(qǐng)求炬太,執(zhí)行服務(wù)
                Result result = invoker.invoke(new RpcInvocation(method, args, inv.getAttachments()));
                。驯耻。亲族。
}

上面的代碼很多,著重來(lái)提取一小段看一下:

Method method = ReflectUtils.findMethodByMethodSignature(invoker.getInterface(), name, types);
Class<?>[] params = method.getParameterTypes();

從上面的代碼中我們便可以得知原來(lái)泛化調(diào)用中使用了Java的反射技術(shù)來(lái)獲取對(duì)應(yīng)的方法信息完成調(diào)用的

4.6 用 Python 來(lái)測(cè)試 Dubbo

我們知道 Dubbo 是個(gè) Java 項(xiàng)目可缚,測(cè)試 Dubbo 就是模擬消費(fèi)者去調(diào)用 Dubbo 的 Java 方法霎迫,那顯而易見(jiàn),用 Python 是肯定沒(méi)法去直接調(diào)用Java的帘靡,但是在日常的工作中知给,很多小伙伴可能是 Pyhton技術(shù)棧的,或者因?yàn)橐恍y(cè)試條件限制亦或歷史原因测柠,必須要將 Dubbo 測(cè)試用 Python 實(shí)現(xiàn)以滿(mǎn)足各種接口測(cè)試的一個(gè)組合。

1. python-hessian庫(kù)

Dubbo是支持hessian+http協(xié)議調(diào)用的缘滥,hessian是一種二進(jìn)制序列化的方式轰胁。
了解到可以通過(guò)這種方式實(shí)現(xiàn),具體沒(méi)有嘗試過(guò)朝扼,還需要開(kāi)發(fā)在項(xiàng)目中將序列化的方式改為hessian赃阀,并且需要知道URL,有興趣的小伙伴可以去了解一下。

2. telnetlib庫(kù)

telnetlib是Python3自帶的一個(gè)庫(kù)榛斯,可以調(diào)用telnet命令观游,其實(shí)也就相當(dāng)于上面說(shuō)到的使用telnet方式訪(fǎng)問(wèn)dubbo的方法

3. 開(kāi)發(fā)dubbo測(cè)試服務(wù)

我們可以使用 Java 來(lái)開(kāi)發(fā)一個(gè) Dubbo 測(cè)試的 Web 服務(wù),實(shí)現(xiàn)上就可以使用 Dubbo 的泛化調(diào)用驮俗,然后我們?cè)儆?HTTP 訪(fǎng)問(wèn)的形式去訪(fǎng)問(wèn)這個(gè)服務(wù)懂缕,將我們的測(cè)試參數(shù)信息傳過(guò)去,剩下的就交給 Java 去處理就好了王凑。

這樣經(jīng)過(guò)封裝設(shè)計(jì)后搪柑,可以實(shí)現(xiàn) Python 端的使用者在訪(fǎng)問(wèn) Dubbo 時(shí)就像在測(cè)試HTTP接口一樣(例如 Python 的request庫(kù));另外服務(wù)的 IP索烹、端口工碾、注冊(cè)中心等信息都不用出現(xiàn)在測(cè)試的工程中,只需要用環(huán)境標(biāo)簽做區(qū)分百姓,在服務(wù)端進(jìn)行請(qǐng)求轉(zhuǎn)發(fā)即可渊额,也保證了一定安全性。

大體上的思路流程如下:


image

以上垒拢,期待與大家多交流學(xué)習(xí)旬迹。

更多技術(shù)文章分享及測(cè)試資料點(diǎn)此獲取

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市子库,隨后出現(xiàn)的幾起案子舱权,更是在濱河造成了極大的恐慌望蜡,老刑警劉巖锥余,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異检疫,居然都是意外死亡仓技,警方通過(guò)查閱死者的電腦和手機(jī)鸵贬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脖捻,“玉大人阔逼,你說(shuō)我怎么就攤上這事〉鼐冢” “怎么了嗜浮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)摩疑。 經(jīng)常有香客問(wèn)我危融,道長(zhǎng),這世上最難降的妖魔是什么雷袋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任吉殃,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛋勺。我一直安慰自己瓦灶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布抱完。 她就那樣靜靜地躺著贼陶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乾蛤。 梳的紋絲不亂的頭發(fā)上每界,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音家卖,去河邊找鬼眨层。 笑死,一個(gè)胖子當(dāng)著我的面吹牛上荡,可吹牛的內(nèi)容都是我干的趴樱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼酪捡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叁征!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起逛薇,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捺疼,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后永罚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體啤呼,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年呢袱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了官扣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羞福,死狀恐怖惕蹄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情治专,我是刑警寧澤卖陵,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站张峰,受9級(jí)特大地震影響泪蔫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挟炬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一鸥滨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谤祖,春花似錦婿滓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至额湘,卻和暖如春卿吐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锋华。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工嗡官, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毯焕。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓衍腥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纳猫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子婆咸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容