源碼解讀Dubbo分層設(shè)計思想
時間:2021-09-16 14:17:49
手機(jī)看文章
掃描二維碼
隨時隨地手機(jī)看文章
[導(dǎo)讀]I作者:vivo互聯(lián)網(wǎng)服務(wù)器團(tuán)隊-WangGenfu一、Dubbo分層整體設(shè)計概述我們先從下圖開始簡單介紹Dubbo分層設(shè)計概念:(引用自Duboo開發(fā)指南-框架設(shè)計文檔)如圖描述Dubbo實現(xiàn)的RPC整體分10層:service、config、proxy、registry、cl...
I作者:vivo互聯(lián)網(wǎng)服務(wù)器團(tuán)隊-Wang Genfu
一、Dubbo分層整體設(shè)計概述
我們先從下圖開始簡單介紹Dubbo分層設(shè)計概念:
(引用自Duboo開發(fā)指南-框架設(shè)計文檔)如圖描述Dubbo實現(xiàn)的RPC整體分10層:service、config、proxy、registry、cluster、monitor、protocol、exchange、transport、serialize。
- service:使用方定義的接口和實現(xiàn)類;
- config:負(fù)責(zé)解析Dubbo定義的配置,比如注解和xml配置,各種參數(shù);
- proxy:主要負(fù)責(zé)生成消費(fèi)者和提供者的代理對象,加載框架功能,比如提供者過濾器鏈,擴(kuò)展點;
- registry:負(fù)責(zé)注冊服務(wù)的定義和實現(xiàn)類的裝載;
- cluster:只有消費(fèi)者有這么一層,負(fù)責(zé)包裝多個服務(wù)提供者成一個‘大提供者’,加載負(fù)載均衡、路有等擴(kuò)展點;
- monitor:定義監(jiān)控服務(wù),加載監(jiān)控實現(xiàn)提供者;
- protocol:封裝RPC調(diào)用接口,管理調(diào)用實體的生命周期;
- exchange:封裝請求響應(yīng)模式,同步轉(zhuǎn)異步;
- transport:抽象傳輸層模型,兼容netty、mina、grizzly等通訊框架;
- serialize:抽象序列化模型,兼容多種序列化框架,包括:fastjson、fst、hessian2、kryo、kryo2、protobuf等,通過序列化支持跨語言的方式,支持跨語言的rpc調(diào)用;
Dubbo這么分層的目的在于實現(xiàn)層與層之間的解耦,每一層都定義了接口規(guī)范,也可以根據(jù)不同的業(yè)務(wù)需求定制、加載不同的實現(xiàn),具有極高的擴(kuò)展性。
1.1. RPC調(diào)用過程
接下來結(jié)合上圖簡單描述一次完整的rpc調(diào)用過程:
從Dubbo分層的角度看,詳細(xì)時序圖如下,藍(lán)色部分是服務(wù)消費(fèi)端,淺綠色部分是服務(wù)提供端,時序圖從消費(fèi)端一次Dubbo方法調(diào)用開始,到服務(wù)端本地方法執(zhí)行結(jié)束。

從Dubbo核心領(lǐng)域?qū)ο蟮慕嵌瓤矗覀円?span>Dubbo官方文檔說明,如下圖所示。Dubbo核心領(lǐng)域?qū)ο笫荌nvoker,消費(fèi)端代理對象是proxy,包裝了Invoker的調(diào)用;服務(wù)端代理對象是一個Invoker,他通過exporter包裝,當(dāng)服務(wù)端接收到調(diào)用請求后,通過exporter找到Invoker,Invoker去實際執(zhí)行用戶的業(yè)務(wù)邏輯。
(引用自Dubbo官方文檔)1.2 Dubbo服務(wù)的注冊和發(fā)現(xiàn)流程
下圖出自開發(fā)指南-框架設(shè)計-引用服務(wù)時序,主要流程是:從注冊中心訂閱服務(wù)提供者,然后啟動tcp服務(wù)連接遠(yuǎn)端提供者,將多個服務(wù)提供者合并成一個Invoker,用這個Invoker創(chuàng)建代理對象。

下圖出自開發(fā)指南-框架設(shè)計-暴露服務(wù)時序,主要流程是:創(chuàng)建本地服務(wù)的代理Invoker,啟動tcp服務(wù)暴露服務(wù),然后將服務(wù)注冊到注冊中心。

接下來我們結(jié)合Dubbo服務(wù)的注冊和發(fā)現(xiàn),從配置層開始解釋每一層的作用和原理。
示例服務(wù)接口定義如下:
public interface CouponServiceViewFacade { /** * 查詢單張優(yōu)惠券 */ CouponViewDTO query(String code);}二、配置層
2.1. 做什么
配置層提供配置處理工具類,在容器啟動的時候,通過ServiceConfig.export實例化服務(wù)提供者,ReferenceConfig.get實例化服務(wù)消費(fèi)者對象。
Dubbo應(yīng)用使用spring容器啟動時,Dubbo服務(wù)提供者配置處理器通過ServiceConfig.export啟動Dubbo遠(yuǎn)程服務(wù)暴露本地服務(wù)。Dubbo服務(wù)消費(fèi)者配置處理器通過ReferenceConfig.get實例化一個代理對象,并通過注冊中心服務(wù)發(fā)現(xiàn),連接遠(yuǎn)端服務(wù)提供者。
Dubbo配置可以使用注解和xml兩種形式,本文采用注解的形式進(jìn)行說明。
2.2. 怎么做
2.2.1 服務(wù)消費(fèi)端的解析
Spring容器啟動過程中,填充bean屬性時,對含有Dubbo引用注解的屬性使用org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor進(jìn)行初始化。
如下是ReferenceAnnotationBeanPostProcessor的構(gòu)造方法,Dubbo服務(wù)消費(fèi)者注解處理器處理以下三個注解:DubboReference.class,?Reference.class,?com.alibaba.dubbo.config.annotation.Reference.class修飾的類。
ReferenceAnnotationBeanPostProcessor類定義:
public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor implements ApplicationContextAware { public ReferenceAnnotationBeanPostProcessor() { super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class); }}Dubbo服務(wù)發(fā)現(xiàn)到這一層,Dubbo即將開始構(gòu)建服務(wù)消費(fèi)者的代理對象,CouponServiceViewFacade接口的代理實現(xiàn)類。
2.2.2 服務(wù)提供端的解析
Spring容器啟動的時候,加載注解@org.apache.dubbo.config.spring.context.annotation.DubboComponentScan指定范圍的類,并初始化;初始化使用dubbo實現(xiàn)的擴(kuò)展點org.apache.dubbo.config.spring.beans.factory.annotation.ServiceClassPostProcessor。
ServiceClassPostProcessor處理的注解類有DubboService.class,Service.class,com.alibaba.dubbo.config.annotation.Service.class。
如下是ServiceClassPostProcessor類定義:
public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { private final static List> serviceAnnotationTypes = asList( DubboService.class,Service.class,com.alibaba.dubbo.config.annotation.Service.class );。。。}等待Spring容器ContextRefreshedEvent事件,啟動Dubbo應(yīng)用服務(wù)監(jiān)聽端口,暴露本地服務(wù)。
Dubbo服務(wù)注冊到這一層,Dubbo即將開始構(gòu)建服務(wù)提供者的代理對象,CouponServiceViewFacade實現(xiàn)類的反射代理類。
三、?代理層
3.1 做什么
為服務(wù)消費(fèi)者生成代理實現(xiàn)實例,為服務(wù)提供者生成反射代理實例。
CouponServiceViewFacade的代理實現(xiàn)實例,消費(fèi)端在調(diào)用query方法的時候,實際上是調(diào)用代理實現(xiàn)實例的query方法,通過他調(diào)用遠(yuǎn)程服務(wù)。
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)// package org.apache.dubbo.common.bytecode; public class proxy1 implements DC, Destroyable, CouponServiceViewFacade, EchoService { public static Method[] methods; private InvocationHandler handler; public proxy1(InvocationHandler var1) { this.handler = var1; } public proxy1() { } public CouponViewDTO query(String var1) { Object[] var2 = new Object[]{var1}; Object var3 = this.handler.invoke(this, methods[0], var2); return (CouponViewDTO)var3; }}CouponServiceViewFacade的反射代理實例,服務(wù)端接收到請求后,通過該實例的Invoke方法最終執(zhí)行本地方法query。
/** * InvokerWrapper */public class AbstractProxyInvoker implements Invoker { // 。。。 public AbstractProxyInvoker(CouponServiceViewFacade proxy, Class type, URL url) { //。。。 this.proxy = proxy; this.type = type; this.url = url; } @Override public Result invoke(Invocation invocation) throws RpcException { //。。。 Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); //。。。 } protected Object doInvoke(CouponServiceViewFacade proxy, String methodName, Class>[] parameterTypes, Object[] arguments) throws Throwable{ //。。。 return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }3.2 怎么做
Dubbo代理工廠接口定義如下,定義了服務(wù)提供者和服務(wù)消費(fèi)者的代理對象工廠方法。服務(wù)提供者代理對象和服務(wù)消費(fèi)者代理對象都是通過工廠方法創(chuàng)建,工廠實現(xiàn)類可以通過SPI自定義擴(kuò)展。
@SPI("javassist")public interface ProxyFactory { // 生成服務(wù)消費(fèi)者代理對象 @Adaptive({PROXY_KEY}) T getProxy(Invoker invoker) throws RpcException; // 生成服務(wù)消費(fèi)者代理對象 @Adaptive({PROXY_KEY}) T getProxy(Invoker invoker, boolean generic) throws RpcException; // 生成服務(wù)提供者代理對象 @Adaptive({PROXY_KEY}) Invoker getInvoker(T proxy, Class type, URL url) throws RpcException ; }3.2.1 服務(wù)消費(fèi)者
3.2.1.1 創(chuàng)建服務(wù)消費(fèi)者代理類
默認(rèn)采用Javaassist代理工廠實現(xiàn),Proxy.getProxy(interfaces)創(chuàng)建代理工廠類,newInstance創(chuàng)建具體代理對象。
public class JavassistProxyFactory extends AbstractProxyFactory { @Override @SuppressWarnings("unchecked") public T getProxy(Invoker invoker, Class>[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } 。。。 }3.2.1.2 服務(wù)消費(fèi)者代理
Dubbo為每個服務(wù)消費(fèi)者生成兩個代理類:代理工廠類,接口代理類。
CouponServiceViewFacade代理工廠類:
public class Proxy1 extends Proxy implements DC { public Proxy1() { } public Object newInstance(InvocationHandler var1) { return new proxy1(var1); }}最終生成的CouponServiceViewFacade的代理對象如下,其中handler的實現(xiàn)類是InvokerInvocationHandler,this.handler.invoke方法發(fā)起Dubbo調(diào)用。
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)// package org.apache.dubbo.common.bytecode; public class proxy1 implements DC, Destroyable, CouponServiceViewFacade, EchoService { public static Method[] methods; private InvocationHandler handler; public proxy1(InvocationHandler var1) { this.handler = var1; } public proxy1() { } public CouponViewDTO query(String var1) { Object[] var2 = new Object[]{var1}; Object var3 = this.handler.invoke(this, methods[0], var2); return (CouponViewDTO)var3; }}3.2.2 服務(wù)提供者
3.2.2.1 創(chuàng)建服務(wù)提供者代理類
默認(rèn)Javaassist代理工廠實現(xiàn),使用Wrapper包裝本地服務(wù)提供者。proxy是實際的服務(wù)提供者實例,即CouponServiceViewFacade的本地實現(xiàn)類,type是接口類定義,URL是injvm協(xié)議URL。
public class JavassistProxyFactory extends AbstractProxyFactory { 。。。 @Override public Invoker getInvoker(T proxy, Class type, URL url) { // 代理包裝類,包裝了本地的服務(wù)提供者 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); // 代理類入口 return new AbstractProxyInvoker(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; } }3.2.2.2 Wrapper包裝類
Dubbo為每個服務(wù)提供者的本地實現(xiàn)生成一個Wrapper代理類,抽象Wrapper類定義如下:
public abstract class Wrapper { 。。。 abstract public Object invokeMethod(Object instance, String mn, Class>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;}具體Wrapper代理類使用字節(jié)碼技術(shù)動態(tài)生成,本地服務(wù)CouponServiceViewFacade的代理包裝類舉例:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)// package org.apache.dubbo.common.bytecode; import com.xxx.CouponServiceViewFacade;import java.lang.reflect.InvocationTargetException;import java.util.Map;import org.apache.dubbo.common.bytecode.ClassGenerator.DC; public class Wrapper25 extends Wrapper implements DC { 。。。 public Wrapper25() { } public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException { CouponServiceViewFacade var5; try { var5 = (CouponServiceViewFacade)var1; } catch (Throwable var8) { throw new IllegalArgumentException(var8); } try { if ("query".equals(var2) 




