dubbo泛化调用-基本认知

    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 testSet(Set set);

    Object testMap(Map map);

    int[] testArray(int[] array);

    String[] testArray2(String[] strings);

    Date testDate(Date date);

    List testList(List 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 testList(List list) {
        return list;
    }


    @Override
    public Set testSet(Set set) {
        return set;
    }

    @Override
    public Object testMap(Map map) {
        return map;
    }

    @Override
    public int[] testArray(int[] array) {
        return array;
    }

    @Override
    public String[] testArray2(String[] strings) {
        return strings;
    }
}
 
  

 上面代码定义了一个接口一个该接口对应的实现类。

 服务端的配置和普通的没区别:provider.xml





    
    

    
    
    
    

    
    

    
    



消费端的配置就有些不同了,consumer.xml





    
    

    
    
    
    

    
    


不同点在于泛化的启用: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,Microservices,微服务-RPC)