dubbo源码实践-protocol层-invoker理解

Posted alf_cee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dubbo源码实践-protocol层-invoker理解相关的知识,希望对你有一定的参考价值。

1概述

Invoker官方解释:

Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实
现,也可能是一个远程的实现,也可能一个集群实现。

1.1 Invoker接口

通过源码可知Invoker接口不是SPI。 可以调用invoke方法执行调用。

Invocation是参数,如:调用那个方法名称、参数的类型、参数的值是什么等信息。

1.2 Invoker的实现类

从下图展示了各个Invoker实现类的作用。

2 例子代码

2.1 调用本地的实现

想象一下应用场景:dubbo服务提供者会先把提供的功能封装到service中,然后配置到dubbo中(注解或xml文件),dubbo就可以调用到这些service了。

问题:各个service的名称和方法都不同、参数也不一致,能用一种通用的方式掉用各个service吗?

解决方法:dubbo使用Invoker本地的实现来解决这个问题。

dubbo提供了两种实现方式JdkProxyFactory和JavassistProxyFactory。

2.1.1 JdkProxyFactory实现方式

InvokerTest类代码

package org.example.dubbo.invoker;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory;
import org.example.test.protocol.AlfService;
import org.example.test.protocol.IAlfService;
/** 本地Invoker使用, 2022/12/29. */
public class InvokerTest 
    public static void main(String[] args) 
        //业务服务类
        AlfService alfService = new AlfService();
        //构造一个空的url
        URLBuilder urlBuilder = new URLBuilder();
        URL url = urlBuilder.build();
        //构造Invocation对象
        RpcInvocation rpcInvocation = new RpcInvocation();
        rpcInvocation.setMethodName("sayHolle");//指定调用的方法名
        Class<?>[] parameterTypes = new Class[1];//指定调用的方法的参数类型
        parameterTypes[0] = String.class;
        rpcInvocation.setParameterTypes(parameterTypes);
        Object[] args1 = new Object[1];//指定调用的方法的参数
        args1[0] = "alf";
        rpcInvocation.setArguments(args1);
        //创建ProxyFactory
        ProxyFactory proxyFactory = new JdkProxyFactory();
        //传入service实例,接口和URL获取Invoker实例
        Invoker<IAlfService> invoker = proxyFactory.getInvoker(alfService, IAlfService.class, url);
        //调用invoker实例
        Result result = invoker.invoke(rpcInvocation);
        //获取service方法返回值
        Object value = result.getValue();
        System.out.println(value);

    

AlfService类

package org.example.test.protocol;

/** 业务类 */
public class AlfService implements IAlfService
    @Override
    public String sayHolle(String hi) 
        System.out.println("AlfService call");
        return "hi " + hi;
    

运行结果,调用了service。

实现原理分析

不管什么service,通过proxyFactory.getInvoker获取到响应的Invoker实例,然后使用统一的invoke(Invocation invocation)方法来调用service。

JdkProxyFactory中的实现方式是通过java的反射实现的上述功能。

2.1.2 JavassistProxyFactory实现方式

只要把上面的代码替换成ProxyFactory proxyFactory = new JavassistProxyFactory(); 即可。

运行结果是一样的。

可以知道方式是通过javassist动态产生的一个Wrapper类的实现,然后编译、加载到JVM中。

产生的Wrapper实现的invokeMethod方法如下:

dubbo的默认实现是JavassistProxyFactory。因为性能更好。

2.2 远程调用

必须得有服务端才运行。这里就不演示了。参考DubboInvoker类实现。

下一篇会有例子。

2.3 集群的调用

集群的Invoker的继承关系如下图。

通过ClusterInvoker类的注释可以看到:

This is the final Invoker type referenced by the RPC proxy on Consumer side.
客户端使用该ClusterInvoker,并且是最外层的Invoker。

A ClusterInvoker holds a group of normal invokers, stored in a Directory, mapping to one Registry.
一个ClusterInvoker通过Directory持有一组普通的Invoker,Directory同时会对应一个注册(参考RegistryDirectory类)。

The ClusterInvoker implementation usually provides LB or HA policies, like FailoverClusterInvoker.
ClusterInvoker提供LB或者HA的功能,如FailoverClusterInvoker类。

In multi-registry subscription scenario, the final ClusterInvoker will referr to several sub ClusterInvokers, with each sub ClusterInvoker representing one Registry. Take ZoneAwareClusterInvoker as an example, it is specially customized for multi-registry use cases: first, pick up one ClusterInvoker, then do LB inside the chose Cluster。
在多注册中心订阅的场景下,一个最外层ClusterInvoker内部可以包含多个子ClusterInvoker,每个子ClusterInvoker代表的一个注册中心。可以参考ZoneAwareClusterInvoker类。

具体的例子请见下一篇文章。

2.4 AsyncToSyncInvoker类异步转同步

This class will work as a wrapper wrapping outside of each protocol invoker.
一个包装类,套在protocol invoker外面。

客户端调用服务端代码时应该是异步的(通过protocol invoker调用的),客户端可以在这个protocol invoker外面套一个AsyncToSyncInvoker,这样就转换到同步了,简化了代码的开发。

3 官方架构图中的Invoker

最开始看这张架构图,对里面3处Invoker不是很理解,现在终于清楚了。

1处:处理集群的Invoker,对外是一个Invoker,内部使用负载均衡等方法来选择一个Invoker(调用远程服务)来调用。

2 处:调用远程的Invoker。

3 处:服务端包装业务service的Invoker。

其实dubbo是一个RPC框架,要解决的就是客户端程序调用服务端程序。

服务端:用Invoker来封装业务service;

客户端:用Invoker来封装远程调用,用Invoker来封装集群。

顺便感叹一下,这个架构图画的真牛!!!

以上是关于dubbo源码实践-protocol层-invoker理解的主要内容,如果未能解决你的问题,请参考以下文章

dubbo源码实践-protocol层例子

dubbo源码实践-protocol层例子

Dubbo 源码解析06_Dubbo 服务调用

Dubbo 源码解析03_Dubbo Protocol&Filter

Dubbo源码阅读笔记4

Dubbo之服务暴露源码分析