Dubbo泛化呼叫

擊水三千里發表於2019-03-21

  dubbo消費端,一般必須依賴服務端提供的api包,服務端api包一旦升級,消費端也要跟著升級(依賴的情況下),不像spring cloud一樣,採用rest協議,對服務端的api依賴幾乎可以沒有,不過dubbo也有rest協議擴充套件,見噹噹網dubbox,也有jsonrpc協議的擴充套件,見https://github.com/apache/incubator-dubbo-rpc-jsonrpc ,都不依賴服務端提供的api包。

    dubbo消費端做到不依賴服務端提供的api,除了rest協議及jsonrpc協議擴充套件,dubbo也有一個功能可以做到,這個功能就是dubbo的泛化呼叫:

   泛化介面呼叫方式主要用於客戶端沒有 API 介面及模型類元的情況,引數及返回值中的所有 POJO 均用 Map 表示,通常用於框架整合,比如:實現一個通用的服務測試框架,可通過 GenericService 呼叫所有服務實現。

                --引文:官方文件http://dubbo.apache.org/#/docs/user/demos/generic-reference.md?lang=zh-cn

 

 泛化呼叫的實現主要涉及到兩個filter類:

    com.alibaba.dubbo.rpc.filter.GenericFilter
     com.alibaba.dubbo.rpc.filter.GenericImplFilter
分別在服務端和消費端做處理。

先看個簡單的例子:

package com.sdcuike.dubbo.learning.service;
 
import com.alibaba.fastjson.JSONObject;
 
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
/**
 * @author sdcuike
 * @date 2018/5/31
 * @since 2018/5/31
 */
public interface HystrixService {
 
    String echo();
 
    int echo(int primitive);
 
    JSONObject testGener(String para);
 
    String testGenerRe(String para);
 
    String test(Par par);
 
    Set<String> testSet(Set<String> set);
 
    Object testMap(Map<String, Object> map);
 
    int[] testArray(int[] array);
 
    String[] testArray2(String[] strings);
 
    Date testDate(Date date);
 
    List<Object> testList(List<Object> list);
 
    public static class Par {
        private String name;
        private int age;
 
        public String getName() {
            return name;
        }
 
        public void setName(String name) {
            this.name = name;
        }
 
        public int getAge() {
            return age;
        }
 
        public void setAge(int age) {
            this.age = age;
        }
    }
 
    public static void main(String[] args) {
        System.out.println(Par.class.toString());
    }
}
package com.sdcuike.dubbo.learning.service.impl;
 
import com.alibaba.fastjson.JSONObject;
import com.sdcuike.dubbo.learning.service.HystrixService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
 
/**
 * @author sdcuike
 * @date 2018/5/31
 * @since 2018/5/31
 */
public class HystrixServiceImpl implements HystrixService {
    private Logger logger = LoggerFactory.getLogger(getClass());
 
    private AtomicLong atomicLong = new AtomicLong(0);
 
    private long startTimeMill = 0;
 
 
    @Override
    public String echo() {
        return "hello no param";
    }
 
    @Override
    public int echo(int primitive) {
        return primitive;
    }
 
    @Override
    public JSONObject testGener(String para) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("para", para);
        return jsonObject;
    }
 
    @Override
    public String testGenerRe(String para) {
 
        return "haha " + para;
    }
 
    @Override
    public String test(Par par) {
        return "wowo " + par.getName() + par.getAge();
    }
 
    @Override
    public Date testDate(Date date) {
        return date;
    }
 
    @Override
    public List<Object> testList(List<Object> list) {
        return list;
    }
 
 
    @Override
    public Set<String> testSet(Set<String> set) {
        return set;
    }
 
    @Override
    public Object testMap(Map<String, Object> map) {
        return map;
    }
 
    @Override
    public int[] testArray(int[] array) {
        return array;
    }
 
    @Override
    public String[] testArray2(String[] strings) {
        return strings;
    }
}

 上面程式碼定義了一個介面一個該介面對應的實現類。

 服務端的配置和普通的沒區別:provider.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"
       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="provider-test"/>
 
    <!-- 使用multicast廣播註冊中心暴露服務地址 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <!-- 用dubbo協議在20880埠暴露服務 -->
    <dubbo:protocol name="dubbo" port="20088" host="127.0.0.1"/>
 
    <!-- 宣告需要暴露的服務介面 -->
    <dubbo:service interface="com.sdcuike.dubbo.learning.service.HystrixService" ref="hystrixService" />
 
    <!-- 和本地bean一樣實現服務 -->
    <bean id="hystrixService" class="com.sdcuike.dubbo.learning.service.impl.HystrixServiceImpl"/>
 
 
</beans>

消費端的配置就有些不同了,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"
       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="consumer-test"/>
 
    <!-- 使用multicast廣播註冊中心暴露服務地址 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:protocol name="dubbo"/>
    <dubbo:consumer timeout="3000" check="false"/>
 
    <!-- 宣告需要暴露的服務介面 -->
    <dubbo:reference id="hystrixService" interface="com.sdcuike.dubbo.learning.service.HystrixService"
                     generic="true"
                     retries="0"/>
 
</beans>

不同點在於泛化的啟用:generic="true"。

寫個測試用例:啟動服務端:

ProviderTest
package com.sdcuike.dubbo.learning.service;
 
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import java.util.concurrent.TimeUnit;
 
/**
 * @author sdcuike
 * @date 2018/5/31
 * @since 2018/5/31
 */
public class ProviderTest {
 
    @Test
    public void test() throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"provider.xml"});
        context.start();
 
        TimeUnit.HOURS.sleep(1);
 
    }
}

消費端測試用例:DubboGenericConsumerXmlTest,

package com.sdcuike.dubbo.learning.service;
 
import com.alibaba.dubbo.rpc.service.GenericService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
/**
 * @author sdcuike
 * @date 2018/7/14
 * @since 2018/7/14
 */
public class DubboGenericConsumerXmlTest {
 
    GenericService hystrixService;
 
    @Before
    public void init() {
 
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"consumer.xml"});
 
        hystrixService = (GenericService) context.getBean("hystrixService");
    }
 
 
    @Test
    public void testGenerRe_引數為基本型別_引數型別傳遞() throws InterruptedException {
 
 
        Object result = hystrixService.$invoke("testGenerRe", new String[]{"java.lang.String"}, new Object[]{"test"});
 
        Assert.assertEquals("haha test", result.toString());
 
    }
 
    @Test
    public void testGenerRe_引數為基本型別_引數型別不傳遞() throws InterruptedException {
 
 
        Object result = hystrixService.$invoke("testGenerRe", null, new Object[]{"test"});
 
        Assert.assertEquals("haha test", result.toString());
 
    }
 
    @Test
    public void test_echo_無引數_有過載方法() {
 
        final Object echo = hystrixService.$invoke("echo", new String[]{}, null);
 
        Assert.assertEquals("hello no param", echo.toString());
    }
 
}

不同以往的消費端服務引用,我們這裡引用的泛化介面com.alibaba.dubbo.rpc.service.GenericService。

再呼叫相應服務方法的時候,我們必須顯示的傳遞方法名及引數,但對於引數型別我們可以不必傳遞, 但方法過載的情況下,我們必須傳遞,稍後會說明原因。

原始碼見:

https://github.com/sdcuike/all_learning_201806/tree/master/dubbo-learning/src/test/java/com/sdcuike/dubbo/learning/service

dubbo泛化呼叫-泛化呼叫平臺 

https://blog.csdn.net/doctor_who2004/article/details/81051226

相關文章