五、调用模块源码分析

概要:

一、Dubbo 调用非典型使用场景

二、调用内部实现源码分析

一、Dubbo 调用非典型使用场景


泛化提供&引用

泛化提供

是指不通过接口的方式直接将服务暴露出去。通常用于Mock框架或服务降级框架实现。
public static void doExportGenericService() {
    ApplicationConfig applicationConfig = new ApplicationConfig();
    applicationConfig.setName("demo-provider");
    // 注册中心
    RegistryConfig registryConfig = new RegistryConfig();
    registryConfig.setProtocol("zookeeper");
    registryConfig.setAddress("192.168.0.147:2181");
    ProtocolConfig protocol=new ProtocolConfig();
    protocol.setPort(-1);
    protocol.setName("dubbo");
    GenericService demoService = new MyGenericService();
    ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();
    // 弱类型接口名
    service.setInterface("com.tuling.teach.service.DemoService");
    // 指向一个通用服务实现
    service.setRef(demoService);
    service.setApplication(applicationConfig);
    service.setRegistry(registryConfig);
    service.setProtocol(protocol);
    // 暴露及注册服务
    service.export();
}

泛化引用
是指不通过常规接口的方式去引用服务,通常用于测试框架。

ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("demo-provider");
// 注册中心
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("192.168.0.147:2181");
// 引用远程服务
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
// 弱类型接口名
reference.setInterface("com.tuling.teach.service.DemoService");
// 声明为泛化接口
reference.setGeneric(true);
reference.setApplication(applicationConfig);
reference.setRegistry(registryConfig);
// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用
GenericService genericService = reference.get();
Object result = genericService.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"world"});

隐示传参

是指通过非常方法参数传递参数,类似于http 调用当中添加cookie值。通常用于分布式追踪框架的实现。使用方式如下 :
//客户端隐示设置值
RpcContext.getContext().setAttachment("index", "1"); // 隐式传参,后面的远程调用都会隐
//服务端隐示获取值
String index = RpcContext.getContext().getAttachment("index"); 

令牌验证

通过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,可以防止消费者绕过注册中心访问提供者,另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者

图片

使用:

<!--随机token令牌,使用UUID生成--><dubbo:provider interface="com.foo.BarService" token="true" />

**过滤器 **

类似于 WEB 中的Filter ,Dubbo本身提供了Filter 功能用于拦截远程方法的调用。其支持自定义过滤器与官方的过滤器使用**:**

#TODO 演示添加日志访问过滤:

<dubbo:provider  filter="accesslog" accesslog="logs/dubbo.log"/>

以上配置 就是 为 服务提供者 添加 日志记录过滤器, 所有访问日志将会集中打印至 accesslog 当中
自定义过滤器:

1、编写过滤器

package com.tuling.dubbo;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

@Activate(group = {CommonConstants.PROVIDER})
public class ProviderHelloFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        System.out.println("hello ok====================================>>>>>");
        return invoker.invoke(invocation);
    }
}

添加扩展点:
创建文件路径如下:

# 文件路径
META-INF/dubbo/org.apache.dubbo.rpc.Filter
#内容:
helloFilter=com.tuling.dubbo.ProviderHelloFilter

二 、调用内部实现源码分析


知识点

  1. 分析代理类
  2. 分析类结构
  3. 初始化过程
  4. 分析代理类

在调用服务端时,是接口的形式进行调用,该接口是Duboo 动态代理之后的实现,通过反编译工具可以查看到其具体实现:

因为类是代理生成,所以采用arthas工具来反编译,具体操作如下:

#运行 arthas
java -jar arthas-boot.jar
#扫描类
sc *.proxy0
#反编译代理类
jad com.alibaba.dubbo.common.bytecode.proxy0

反编译的代码如下:

/*
 * Decompiled with CFR.
 *
 * Could not load the following classes:
 *  com.tuling.client.User
 *  com.tuling.client.UserService
 */
package org.apache.dubbo.common.bytecode;
import com.alibaba.dubbo.rpc.service.EchoService;
import com.tuling.client.User;
import com.tuling.client.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.dubbo.common.bytecode.ClassGenerator;
public class proxy0
implements ClassGenerator.DC,
EchoService,
UserService {
    public static Method[] methods;
    private InvocationHandler handler;
    public List findUser(String string, String string2) {
        Object[] arrobject = new Object[]{string, string2};
        Object object = this.handler.invoke(this, methods[0], arrobject);
        return (List)object;
    }
    public User getUser(Integer n) {
        Object[] arrobject = new Object[]{n};
        Object object = this.handler.invoke(this, methods[1], arrobject);
        return (User)object;
    }
    @Override
    public Object $echo(Object object) {
        Object[] arrobject = new Object[]{object};
        Object object2 = this.handler.invoke(this, methods[2], arrobject);
        return object2;
    }
    public proxy0() {
    }
    public proxy0(InvocationHandler invocationHandler) {
        this.handler = invocationHandler;
    }
}

可看出其代理实现了 UserService 接口。并且基于InvocationHandler 进行代理。实际类是 InvokerInvocationHandler 并且其中之属性为Invoker.。也就是说最终会调用Invoker进行远程调用。

2.Dubbo调用流程:

基础流程:

图片

  1. 客户端调用

  2. 透明代理

  3. 负载均衡

  4. 容错

  5. 异步转同步

  6. 获取结果

  7. 服务端响应

  8. 分析类结构关系

  • prxoy$: 代理类
  • Invoker: 执行器
  • Invocation: 执行参数与环境
  • Result:返回结果
  • Protocol:协议

调用过程

在这里插入图片描述

调用堆栈

//------ 6协议 调用
doInvoke:77, DubboInvoker {org.apache.dubbo.rpc.protocol.dubbo}
invoke:155, AbstractInvoker {org.apache.dubbo.rpc.protocol}
//------ 5异步转同步
invoke:52, AsyncToSyncInvoker {org.apache.dubbo.rpc.protocol} // 异步转同步 ,返回结果之前进行阻塞调用线程
//----- 4过滤器链
invoke:92, MonitorFilter {org.apache.dubbo.monitor.support} // 过滤链-> 监控器
invoke:54, FutureFilter {org.apache.dubbo.rpc.protocol.dubbo.filter} //过滤链-> 回调参数
invoke:14, ProviderHelloFilter {com.tuling.dubbo} // 过滤链-> 自定义过滤器
invoke:60, ConsumerContextFilter {org.apache.dubbo.rpc.filter} // 过滤链-> 消费者环境初始化
//------3集群处理
doInvoke:82, FailoverClusterInvoker {org.apache.dubbo.rpc.cluster.support} // 集服-失败重试
invoke:248, AbstractClusterInvoker {org.apache.dubbo.rpc.cluster.support} //
//----- Mock服务
invoke:78, MockClusterInvoker {org.apache.dubbo.rpc.cluster.support.wrapper} // mock 服务
//----- 2动态代理 --透明化
invoke:55, InvokerInvocationHandler {org.apache.dubbo.rpc.proxy}// 代理的中间接口
getUser:-1, proxy0 {org.apache.dubbo.common.bytecode} // 代理对象
//----- 1调用客户端
main:53, DubboClient {com.tuling.dubbo} // 客户端

协议—>(注册协议)—>MockClusterInvoker —>ClusterInvoker—> RegistryDirectory —>(DubboProtcol)->FilterChain–>DubboInvoker

猜你喜欢

转载自blog.csdn.net/qq_39513430/article/details/108372199