手记

Dubbo 泛化引用

前言

大家好,今天开始给大家分享 — Dubbo 专题之 Dubbo 泛化引用。在前一个章节中我们介绍了 Dubbo 中的参数验证以及使用场景。我们在这个章节会继续介绍 Dubbo 泛化引用。那么什么是泛化引用呢?泛化引用有什么作用呢?下面就让我详细了解下吧!

1. 泛化引用简介

在前面的章节中我们编写的 Dubbo 服务都是基于 API 接口,例如:com.muke.dubbocourse.common.api.BookFacade接口。我们在日常开发中的步骤都是首先定义好暴露服务的 API 接口,然后把这个接口打包成 jar 提供给服务调用方。也就是说通常情况下我们的服务调用方都会依赖我们定义的 API 接口编程。那么在 Dubbo 中为我们提供一种不需要依赖 API 接口的方式进行服务调用,这种方式就泛化引用。其表示类为GenericService

2. 使用方式

在这里我们主要介绍两种使用方式:

  1. 通过Spring使用泛化引用
  • 配置 XML 文件中的服务引用为generic="true"

    <dubbo:reference id="barService" interface="com.muke.dubbocourse.common.api.BookFacade" generic="true" />
    
  • 在代码中使用泛化调用

    GenericService barService = (GenericService) applicationContext.getBean("bookFacade");
    Object result = barService.$invoke("queryAll", null, null);
    
  1. 通过 Java API方式使用
// 引用远程服务 
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); 
// 弱类型接口名
reference.setInterface("com.muke.dubbocourse.common.api.BookFacade");  
reference.setVersion("0.0.1");
// 声明为泛化接口 
reference.setGeneric(true);  

// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用  
GenericService genericService = reference.get(); 

// 如果返回实体对象将自动转成Map 
Object result = genericService.$invoke("queryByName",new String[]
{"com.muke.dubbocourse.common.api.RequestParameter"}, new Object[]{parameter}); 


3. 使用场景

从泛化引用本身我们可以知道它是不需要 API 接口,也就是说泛化引用使用场景在服务提供方没有明确的 API 接口提供的情况下我们都可以使用。通常用于框架集成,比如:实现一个 Dubbo 服务对外统一网,就可通过 GenericService 调用后端所有服务实现。 例如:

在上面的图中客户端通过统一的Dubbo网关访问后端所有的 Dubbo 服务,这里就是使用 泛化调用实现。

4. 示例演示

下面我们通过两种方式来演示一个获取图书列表的服务。

  1. 使用 Spring 泛化引用
  • 主要看消费端 XML 配置文件dubbo-consumer-xml.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
        <dubbo:application name="demo-consumer" logger="log4j"/>
    
        <!--使用zookeeper注册中心-->
        <dubbo:registry address="zookeeper://127.0.0.1:2181" />
        <!--设置generic="true"-->
        <dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade" generic="true"></dubbo:reference>
    
    </beans>
    
  • 消费端 Java 代码

    public class XmlApplication {
    
        public static void main(String[] args) throws IOException {
    
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("generic/consumer/spring/dubbo-consumer-xml.xml");
    
            context.start();
    
          	//创建泛化调用对象
            GenericService bookFacade = (GenericService) context.getBean("bookFacade");
    
            RequestParameter parameter = new RequestParameter();
    
            parameter.setName("SpringBoot");
    				//泛化调用 第一个参数:方法名称,第二个参数:请求参数类型的数组,第三方个参数:请求参数值的数组
            Object result = bookFacade.$invoke("queryByName", new String[] { "com.muke.dubbocourse.common.api.RequestParameter" }, new Object[] { parameter });
    
            System.out.println("Result=>"+result);
    
            System.in.read();
    
        }
    
    }
    
  1. 使用 Java API 方式
public class XmlApplication2 {

    public static void main(String[] args) throws IOException {

        // 引用远程服务
        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
        // 弱类型接口名
        reference.setInterface("com.muke.dubbocourse.common.api.BookFacade");

        //注册中心配置
        RegistryConfig registryConfig = new RegistryConfig();

        registryConfig.setAddress("zookeeper://127.0.0.1:2181");

        reference.setRegistry(registryConfig);

        //应用配置
        ApplicationConfig applicationConfig = new ApplicationConfig();

        applicationConfig.setName("demo-consumer");

        reference.setApplication(applicationConfig);
        // 声明为泛化接口
        reference.setGeneric(true);

        // 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
        GenericService genericService = reference.get();

        RequestParameter parameter = new RequestParameter();

        parameter.setName("SpringBoot");

        Object result = genericService.$invoke("queryByName", new String[]{"com.muke.dubbocourse.common.api.RequestParameter"}, new Object[]{parameter});

        System.out.println("Result=>" + result);

        System.in.read();

    }

}

在上面的代码中我们通过 Java API的方式配置了注册中心、应用配置。在调用服务的使用和上面的Spring使用方式类似使用org.apache.dubbo.rpc.service.GenericService#$invoke方法。

5. 实现原理

在上面的代码GenericService genericService = reference.get()中会调用到org.apache.dubbo.config.ReferenceConfig#init方法,而在此方法中org.apache.dubbo.config.ReferenceConfig#createProxy方法创建一个服务调用代理对象。当我们调用genericService.$invoke方法是实际调用的是org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke方法然后调用org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke调用我们org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke在此方法中就查找我们的调用远程的 Invoker 对象,时序图如下:

6. 小结

在本小节中我们主要学习了 Dubbo 中泛化引用和使用场景,以及使用 Spring 的方式和基于 Java API 的方式使用泛化引用。同时也分析了泛化引用实现的原理,其实就是通过ReferenceConfig包装接口名称、调用方法以及参数名称和参数值,再创建GenericService代理对象然后调用一系列的 Invoker 对象。

本节课程的重点如下:

  1. 理解 Dubbo 中泛化引用

  2. 了解了两种泛化引用使用方式

  3. 了解泛化引用实现原理

  4. 了解泛化引用使用场景

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。

0人推荐
随时随地看视频
慕课网APP