Dubbo客户端实现整体逻辑梳理

前言

  1. 在没有看dubbo源码前,很好奇为啥@DubboReference修饰后就会增加Dubbo相关的功能,它是如何实现?下面就对其做一个整体回顾总结
  2. 步骤
    2.1 扫描bean,将@DubboReference注解修饰的属性向spring容器注册ReferenceBean的BeanDefinition
    2.2 getBean:根据BeanDefinition创建一个ReferenceBean并触发其afterPropertiesSet,创建ReferenceConfig并放入ModuleConfigManager中
    2.3 通过反射将属性重新指定为ReferenceBean,ReferenceBean实现FactoryBean接口,在getObject方法通过referenceConfig.get()创建代理
    2.4 监听容器启动事件,初始化ReferenceConfig:创建Invoker以及代理
  3. 根据上面步骤总结可以看出因为dubbo对@DubboReference修饰的属性创建了代理,对其功能做了增强

创建代理

  1. 创建代理的入口在ReferenceAnnotationBeanPostProcessor

  2. ReferenceAnnotationBeanPostProcessor实现BeanFactoryPostProcessor接口,在postProcessBeanFactory方法时扫描spring容器所有的bean
    2.1 反射寻找beanClass被指定注解修饰的属性
    在这里插入图片描述
    2.2 遍历该类中被@DubboReference修饰的属性列表,将其注册为ReferenceBean的RootBeanDefinition

  3. ReferenceAnnotationBeanPostProcessor实现MergedBeanDefinitionPostProcessor接口,在postProcessMergedBeanDefinition方法时将构建bean的元数据(属性、方法)并将其放入缓存injectionMetadataCache中

  4. ReferenceAnnotationBeanPostProcessor继承InstantiationAwareBeanPostProcessorAdapter类,在postProcessPropertyValues方法时从缓存中获取该bean的元数据,getBean触发根据beanDefinition创建一个ReferenceBean

    // AbstractAnnotationBeanPostProcessor#inject
    protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
    	// return getBeanFactory().getBean((String) injectedElement.injectedObject);
    	Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(), this);
    	if (member instanceof Field) {
    		  // 反射重新指定
              Field field = (Field) member;
              ReflectionUtils.makeAccessible(field);
              field.set(bean, injectedObject);
        }
    }
    

    4.1 ReferenceBean实现InitializingBean接口,在afterPropertiesSet方法创建ReferenceConfig并放入ModuleConfigManager中
    4.2 ReferenceBean实现FactoryBean接口,在getObject方法时会创建代理

    private void createLazyProxy() {
    	ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
        proxyFactory.addInterface(interfaceClass);
        this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
    }
    

    4.3 在调用时触发DubboReferenceLazyInitTargetSource创建代理referenceConfig.get()

  5. DubboDeployApplicationListener实现ApplicationListener接口,监听容器启动事件,遍历ModuleConfigManager中的ReferenceConfig列表,调用Init方法进行初始化
    5.1 创建Invoker,默认Cluster的扩展为FailoverCluster
    5.2 创建代理

服务代理

  1. 整体介绍AbstractInvoker#invoke
    public Result invoke(Invocation inv) throws RpcException {
    	// 发起rpc请求并返回异步结果
        AsyncRpcResult asyncResult = doInvokeAndReturn(invocation);
        // 如果是同步则等待rpc结果
        waitForResultIfSync(asyncResult, invocation);
        return asyncResult;
    }
    
  2. 发送请求:DubboInvoker#doInvoke
    protected Result doInvoke(final Invocation invocation) throws Throwable {
    	// 根据客户端端口获取其线程池
    	ExecutorService executor = getCallbackExecutor(getUrl(), inv);
    	// 通过channel发送数据,将请求ID与future绑定,为future设置线程池
        CompletableFuture<AppResponse> appResponseFuture =
                        currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
    }
    
  3. 同步等待返回
    3.1 从ThreadlessExecutor的阻塞队列取出任务并执行解析以及处理响应
    3.2 将结果写入future中

伪代码简写整个过程

  1. 发送请求
    1.1 初始化异步结果CompletableFuture并与请求ID建立映射关系
    1.2 通过channel发送数据
  2. 接收响应
    2.1 netty接收到响应后,根据响应ID找到对应异步结果
    2.2 将响应写入异步结果
    class dubbo{
    	// 请求ID与异步结果映射
    	Map<String,CompletableFuture> futures = new ConcurrentHashMap<>();
    	// 请求ID与channel映射
    	Map<String,Channel> channels = new ConcurrentHashMap<>();
    	
    	// 异步发送请求
    	public CompletableFuture dubboRpc(){
    		CompletableFuture future = new CompletableFuture();
    		futures.put(request.getId(), future);
    		channels.put(request.getId(),channel);
    		// 发送请求
    	    channel.send(req);  
    	    // 完成请求后,将响应做墙砖
    	    future.thenApply(obj -> (AppResponse) obj);
    	    return future
    	}
    
    	public AppResponse handleResponse(){
    		// netty收到响应后,根据id找到对应异步结果
    		String id = response.getId();
    		CompletableFuture future = futures.get(id);
    		// 将响应写入异步结果
    		future.complete(response)
    		// 获取异步结果
    		return future.get();
    	}
    
    }
    
    

总结

   本篇文章主要分析dubbo怎样增强@DubboReference修饰的属性,学习dubbo怎样实战反射、代理以及在dubbo如何根据spring周期去做扩展。在远程调用环节分析了dubbo怎样使用CompletableFuture异步处理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值