当后端Java服务用Dubbo协议做为RPC方案的基础,但部分消费方是前端Restful的PHP服务,不能直接调用,因而在中间架设了Router服务提供统一的基于HTTP的后端调用入口。
而Router调用后端Java服务就应用了Dubbo的高级特性--泛化调用前端
本文将用一个小Demo来演示上面所述的泛化调用应用场景java
DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,天天为2,000+个服务提供3,000,000,000+次访问量支持,并被普遍应用于阿里巴巴集团的各成员站点。
-- Dubbo官方描述webDubbo能作什么:
-- 《Dubbo功能介绍》(官方资料)spring
注:Dubbo的基本使用介绍不在本文范畴,若有须要请自行参考官方资料编程
泛接口调用方式主要用于客户端没有API接口及模型类元的状况,参数及返回值中的全部POJO均用Map表示,一般用于框架集成,好比:实现一个通用的服务测试框架,可经过GenericService调用全部服务实现。
-- Dubbo用户指南json
public interface UserInfoService { public Map<String, String> getUser(String id); public Map<String, String>[] getUsers(); }
dubboconf.properties:
后端
application.name=router registry.address=zookeeper://address1?buckup=address2,address3
{ "interfaceName": "foo", "methodName": "bar", "methodParams": [ { "id": "xxx" } ] }
RequestDto.java:
api
import java.util.Map; /** * Created by Luo */ public class RequestDto { private String interfaceName; private String methodName private Map[] methodParams; public String getInterfaceName() { return interfaceName; } public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Map[] getMethodParams() { return methodParams; } public void setMethodParam(Map[] methodParams) { this.methodParams = methodParams; } }
RouterController.java:
缓存
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by Luo */ @RestController public class App { @RequestMapping(value = "/router/", method = RequestMethod.POST) public Object getUser(@ModelAttribute RequestDto dto) { Map map = new HashMap<>(); map.put("ParamType", "java.lang.String"); //后端接口参数类型 map.put("Object", dto.getMethodParams()[0].get("id")); //用以调用后端接口的实参 List<Map<String, Object>> paramInfos= new ArrayList<>(); paramInfos.add(map); DubboServiceFactory dubbo = DubboServiceFactory.getInstance(); return dubbo.genericInvoke(dto.getInterfaceName(), dto.getMethodName(), paramInfos); } }
注:本文旨在演示泛化调用的一种应用方式,为简明起见,代码中直接从dto中获取了指定参数,而并无完整实现其路由功能,望见谅。app
DubboServiceFactory.java
package local.demo.genericservice; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ReferenceConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.utils.ReferenceConfigCache; import com.alibaba.dubbo.rpc.service.GenericService; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Properties; /** * Created by Luo */ public class DubboServiceFactory { private ApplicationConfig application; private RegistryConfig registry; private static class SingletonHolder { private static DubboServiceFactory INSTANCE = new DubboServiceFactory(); } private DubboServiceFactory(){ Properties prop = new Properties(); ClassLoader loader = DubboServiceFactory.class.getClassLoader(); try { prop.load(loader.getResourceAsStream("dubboconf.properties")); } catch (IOException e) { e.printStackTrace(); } ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName(prop.getProperty("application.name")); //这里配置了dubbo的application信息*(demo只配置了name)*,所以demo没有额外的dubbo.xml配置文件 RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress(prop.getProperty("registry.address")); //这里配置dubbo的注册中心信息,所以demo没有额外的dubbo.xml配置文件 this.application = applicationConfig; this.registry = registryConfig; } public static DubboServiceFactory getInstance() { return SingletonHolder.INSTANCE; } public Object genericInvoke(String interfaceClass, String methodName, List<Map<String, Object>> parameters){ ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); reference.setApplication(application); reference.setRegistry(registry); reference.setInterface(interfaceClass); // 接口名 reference.setGeneric(true); // 声明为泛化接口 //ReferenceConfig实例很重,封装了与注册中心的链接以及与提供者的链接, //须要缓存,不然重复生成ReferenceConfig可能形成性能问题而且会有内存和链接泄漏。 //API方式编程时,容易忽略此问题。 //这里使用dubbo内置的简单缓存工具类进行缓存 ReferenceConfigCache cache = ReferenceConfigCache.getCache(); GenericService genericService = cache.get(reference); // 用com.alibaba.dubbo.rpc.service.GenericService能够替代全部接口引用 int len = parameters.size(); String[] invokeParamTyeps = new String[len]; Object[] invokeParams = new Object[len]; for(int i = 0; i < len; i++){ invokeParamTyeps[i] = parameters.get(i).get("ParamType") + ""; invokeParams[i] = parameters.get(i).get("Object"); } return genericService.$invoke(methodName, invokeParamTyeps, invokeParams); } }
将Router部署到Jetty/Tomcat等容器,或者直接使用SpringBoot开发,发布为内嵌Jetty/Tomcat的独立jar包,便可向前端服务提供服务。