前言
- 在没有看dubbo源码前,很好奇为啥@DubboReference修饰后就会增加Dubbo相关的功能,它是如何实现?下面就对其做一个整体回顾总结
- 步骤
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以及代理 - 根据上面步骤总结可以看出因为dubbo对@DubboReference修饰的属性创建了代理,对其功能做了增强
创建代理
-
创建代理的入口在ReferenceAnnotationBeanPostProcessor
-
ReferenceAnnotationBeanPostProcessor实现BeanFactoryPostProcessor接口,在postProcessBeanFactory方法时扫描spring容器所有的bean
2.1 反射寻找beanClass被指定注解修饰的属性
2.2 遍历该类中被@DubboReference修饰的属性列表,将其注册为ReferenceBean的RootBeanDefinition -
ReferenceAnnotationBeanPostProcessor实现MergedBeanDefinitionPostProcessor接口,在postProcessMergedBeanDefinition方法时将构建bean的元数据(属性、方法)并将其放入缓存injectionMetadataCache中
-
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()
-
DubboDeployApplicationListener实现ApplicationListener接口,监听容器启动事件,遍历ModuleConfigManager中的ReferenceConfig列表,调用Init方法进行初始化
5.1 创建Invoker,默认Cluster的扩展为FailoverCluster
5.2 创建代理
服务代理
- 整体介绍AbstractInvoker#invoke
public Result invoke(Invocation inv) throws RpcException { // 发起rpc请求并返回异步结果 AsyncRpcResult asyncResult = doInvokeAndReturn(invocation); // 如果是同步则等待rpc结果 waitForResultIfSync(asyncResult, invocation); return asyncResult; }
- 发送请求: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.1 从ThreadlessExecutor的阻塞队列取出任务并执行解析以及处理响应
3.2 将结果写入future中
伪代码简写整个过程
- 发送请求
1.1 初始化异步结果CompletableFuture并与请求ID建立映射关系
1.2 通过channel发送数据 - 接收响应
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异步处理