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
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