美文网首页互联网科技程序员Java 杂谈
Dubbo 高级特性实践-泛化调用

Dubbo 高级特性实践-泛化调用

作者: Java高级架构狮 | 来源:发表于2018-09-13 15:06 被阅读13次

    引言

    当后端Java服务用Dubbo协议作为RPC方案的基础,但部分消费方是前端Restful的PHP服务,不能直接调用,于是在中间架设了Router服务提供统一的基于HTTP的后端调用入口。

    而Router调用后端Java服务就应用了Dubbo的高级特性–泛化调用

    直接消费方(Router服务)不需要引入接口jar包

    通过GenericService接口来处理所有服务请求

    以PHP到Router的request body中的方法名和方法参数作为Router远程调用后端Java服务的入参,最后将远程调用的result返回给PHP端

    本文将用一个小Demo来演示上面所述的泛化调用应用场景

    零.Dubbo简介

    DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    – Dubbo官方描述

    Dubbo能做什么:

    ①、透明化的远程方法调用

    就像调用本地方法一样调用远程方法

    只需简单配置,没有任何API侵入。

    ②、软负载均衡及容错机制

    可在内网替代F5等硬件负载均衡器

    ③、服务自动注册与发现

    不再需要写死服务提供方地址,注册中心基于接口名查询服务提 供者的IP地址,并且能够平滑添加或删除服务提供者

    – 《Dubbo功能介绍》(官方资料)

    注:Dubbo的基本使用介绍不在本文范畴,如有需要请自行参考官方资料

    泛接口调用方式主要用于客户端没有API接口及模型类元的情况,参数及返回值中的所有POJO均用Map表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过GenericService调用所有服务实现。

    – Dubbo用户指南

    一、后端API

    public interface UserInfoService {

    public Map getUser(String id);

    public Map[] getUsers();

    }

    二、Router端dubbo配置

    dubboconf.properties:

    application.name=router

    registry.address=zookeeper://address1?buckup=address2,address3

    三、前端服务post到Router的Request Body示例:

    {

    "interfaceName": "foo",

    "methodName": "bar",

    "methodParams": [

    {

    "id": "xxx"

    }

    ]

    }

    四、处理前端参数用的Dto

    RequestDto.java:

    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;

    }

    }

    五、Router服务入口

    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> paramInfos= new ArrayList<>();

    paramInfos.add(map);

    DubboServiceFactory dubbo = DubboServiceFactory.getInstance();

    return dubbo.genericInvoke(dto.getInterfaceName(), dto.getMethodName(), paramInfos);

    }

    }

    注:本文旨在演示泛化调用的一种应用方式,为简明起见,代码中直接从dto中获取了指定参数,而并没有完整实现其路由功能,望见谅。

    六、通过GenericService进行泛化调用

    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> parameters){

    ReferenceConfig reference = new ReferenceConfig();

    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包,即可向前端服务提供服务。

    写在最后:欢迎留言讨论,加关注,持续更新!!!

    相关文章

      网友评论

        本文标题:Dubbo 高级特性实践-泛化调用

        本文链接:https://www.haomeiwen.com/subject/hobwgftx.html