源碼解讀Dubbo分層設(shè)計(jì)思想
時(shí)間:2021-09-16 14:17:49
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
[導(dǎo)讀]I作者:vivo互聯(lián)網(wǎng)服務(wù)器團(tuán)隊(duì)-WangGenfu一、Dubbo分層整體設(shè)計(jì)概述我們先從下圖開(kāi)始簡(jiǎn)單介紹Dubbo分層設(shè)計(jì)概念:(引用自Duboo開(kāi)發(fā)指南-框架設(shè)計(jì)文檔)如圖描述Dubbo實(shí)現(xiàn)的RPC整體分10層:service、config、proxy、registry、cl...
I作者:vivo互聯(lián)網(wǎng)服務(wù)器團(tuán)隊(duì)-Wang Genfu
一、Dubbo分層整體設(shè)計(jì)概述
我們先從下圖開(kāi)始簡(jiǎn)單介紹Dubbo分層設(shè)計(jì)概念:

如圖描述Dubbo實(shí)現(xiàn)的RPC整體分10層:service、config、proxy、registry、cluster、monitor、protocol、exchange、transport、serialize。
- service:使用方定義的接口和實(shí)現(xiàn)類;
- config:負(fù)責(zé)解析Dubbo定義的配置,比如注解和xml配置,各種參數(shù);
- proxy:主要負(fù)責(zé)生成消費(fèi)者和提供者的代理對(duì)象,加載框架功能,比如提供者過(guò)濾器鏈,擴(kuò)展點(diǎn);
- registry:負(fù)責(zé)注冊(cè)服務(wù)的定義和實(shí)現(xiàn)類的裝載;
- cluster:只有消費(fèi)者有這么一層,負(fù)責(zé)包裝多個(gè)服務(wù)提供者成一個(gè)‘大提供者’,加載負(fù)載均衡、路有等擴(kuò)展點(diǎn);
- monitor:定義監(jiān)控服務(wù),加載監(jiān)控實(shí)現(xiàn)提供者;
- protocol:封裝RPC調(diào)用接口,管理調(diào)用實(shí)體的生命周期;
- exchange:封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步;
- transport:抽象傳輸層模型,兼容netty、mina、grizzly等通訊框架;
- serialize:抽象序列化模型,兼容多種序列化框架,包括:fastjson、fst、hessian2、kryo、kryo2、protobuf等,通過(guò)序列化支持跨語(yǔ)言的方式,支持跨語(yǔ)言的rpc調(diào)用;
Dubbo這么分層的目的在于實(shí)現(xiàn)層與層之間的解耦,每一層都定義了接口規(guī)范,也可以根據(jù)不同的業(yè)務(wù)需求定制、加載不同的實(shí)現(xiàn),具有極高的擴(kuò)展性。
1.1. RPC調(diào)用過(guò)程
接下來(lái)結(jié)合上圖簡(jiǎn)單描述一次完整的rpc調(diào)用過(guò)程:
從Dubbo分層的角度看,詳細(xì)時(shí)序圖如下,藍(lán)色部分是服務(wù)消費(fèi)端,淺綠色部分是服務(wù)提供端,時(shí)序圖從消費(fèi)端一次Dubbo方法調(diào)用開(kāi)始,到服務(wù)端本地方法執(zhí)行結(jié)束。

從Dubbo核心領(lǐng)域?qū)ο蟮慕嵌瓤?,我們引?span>Dubbo官方文檔說(shuō)明,如下圖所示。Dubbo核心領(lǐng)域?qū)ο笫荌nvoker,消費(fèi)端代理對(duì)象是proxy,包裝了Invoker的調(diào)用;服務(wù)端代理對(duì)象是一個(gè)Invoker,他通過(guò)exporter包裝,當(dāng)服務(wù)端接收到調(diào)用請(qǐng)求后,通過(guò)exporter找到Invoker,Invoker去實(shí)際執(zhí)行用戶的業(yè)務(wù)邏輯。

1.2 Dubbo服務(wù)的注冊(cè)和發(fā)現(xiàn)流程
下圖出自開(kāi)發(fā)指南-框架設(shè)計(jì)-引用服務(wù)時(shí)序,主要流程是:從注冊(cè)中心訂閱服務(wù)提供者,然后啟動(dòng)tcp服務(wù)連接遠(yuǎn)端提供者,將多個(gè)服務(wù)提供者合并成一個(gè)Invoker,用這個(gè)Invoker創(chuàng)建代理對(duì)象。

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

接下來(lái)我們結(jié)合Dubbo服務(wù)的注冊(cè)和發(fā)現(xiàn),從配置層開(kāi)始解釋每一層的作用和原理。
示例服務(wù)接口定義如下:
public interface CouponServiceViewFacade {
/**
* 查詢單張優(yōu)惠券
*/
CouponViewDTO query(String code);
}
二、配置層
2.1. 做什么
配置層提供配置處理工具類,在容器啟動(dòng)的時(shí)候,通過(guò)ServiceConfig.export實(shí)例化服務(wù)提供者,ReferenceConfig.get實(shí)例化服務(wù)消費(fèi)者對(duì)象。
Dubbo應(yīng)用使用spring容器啟動(dòng)時(shí),Dubbo服務(wù)提供者配置處理器通過(guò)ServiceConfig.export啟動(dòng)Dubbo遠(yuǎn)程服務(wù)暴露本地服務(wù)。Dubbo服務(wù)消費(fèi)者配置處理器通過(guò)ReferenceConfig.get實(shí)例化一個(gè)代理對(duì)象,并通過(guò)注冊(cè)中心服務(wù)發(fā)現(xiàn),連接遠(yuǎn)端服務(wù)提供者。
Dubbo配置可以使用注解和xml兩種形式,本文采用注解的形式進(jìn)行說(shuō)明。
2.2. 怎么做
2.2.1 服務(wù)消費(fèi)端的解析
Spring容器啟動(dòng)過(guò)程中,填充bean屬性時(shí),對(duì)含有Dubbo引用注解的屬性使用org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor進(jìn)行初始化。
如下是ReferenceAnnotationBeanPostProcessor的構(gòu)造方法,Dubbo服務(wù)消費(fèi)者注解處理器處理以下三個(gè)注解: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即將開(kāi)始構(gòu)建服務(wù)消費(fèi)者的代理對(duì)象,CouponServiceViewFacade接口的代理實(shí)現(xiàn)類。
2.2.2 服務(wù)提供端的解析
Spring容器啟動(dòng)的時(shí)候,加載注解@org.apache.dubbo.config.spring.context.annotation.DubboComponentScan指定范圍的類,并初始化;初始化使用dubbo實(shí)現(xiàn)的擴(kuò)展點(diǎn)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事件,啟動(dòng)Dubbo應(yīng)用服務(wù)監(jiān)聽(tīng)端口,暴露本地服務(wù)。
Dubbo服務(wù)注冊(cè)到這一層,Dubbo即將開(kāi)始構(gòu)建服務(wù)提供者的代理對(duì)象,CouponServiceViewFacade實(shí)現(xiàn)類的反射代理類。
三、?代理層
3.1 做什么
為服務(wù)消費(fèi)者生成代理實(shí)現(xiàn)實(shí)例,為服務(wù)提供者生成反射代理實(shí)例。
CouponServiceViewFacade的代理實(shí)現(xiàn)實(shí)例,消費(fèi)端在調(diào)用query方法的時(shí)候,實(shí)際上是調(diào)用代理實(shí)現(xiàn)實(shí)例的query方法,通過(guò)他調(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的反射代理實(shí)例,服務(wù)端接收到請(qǐng)求后,通過(guò)該實(shí)例的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)者的代理對(duì)象工廠方法。服務(wù)提供者代理對(duì)象和服務(wù)消費(fèi)者代理對(duì)象都是通過(guò)工廠方法創(chuàng)建,工廠實(shí)現(xiàn)類可以通過(guò)SPI自定義擴(kuò)展。
@SPI("javassist")
public interface ProxyFactory {
// 生成服務(wù)消費(fèi)者代理對(duì)象
@Adaptive({PROXY_KEY})
T getProxy(Invoker invoker) throws RpcException;
// 生成服務(wù)消費(fèi)者代理對(duì)象
@Adaptive({PROXY_KEY})
T getProxy(Invoker invoker, boolean generic) throws RpcException;
// 生成服務(wù)提供者代理對(duì)象
@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代理工廠實(shí)現(xiàn),Proxy.getProxy(interfaces)創(chuàng)建代理工廠類,newInstance創(chuàng)建具體代理對(duì)象。
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為每個(gè)服務(wù)消費(fèi)者生成兩個(gè)代理類:代理工廠類,接口代理類。
CouponServiceViewFacade代理工廠類:
public class Proxy1 extends Proxy implements DC {
public Proxy1() {
}
public Object newInstance(InvocationHandler var1) {
return new proxy1(var1);
}
}
最終生成的CouponServiceViewFacade的代理對(duì)象如下,其中handler的實(shí)現(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代理工廠實(shí)現(xiàn),使用Wrapper包裝本地服務(wù)提供者。proxy是實(shí)際的服務(wù)提供者實(shí)例,即CouponServiceViewFacade的本地實(shí)現(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為每個(gè)服務(wù)提供者的本地實(shí)現(xiàn)生成一個(gè)Wrapper代理類,抽象Wrapper類定義如下:
public abstract class Wrapper {
。。。
abstract public Object invokeMethod(Object instance, String mn, Class>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
}
具體Wrapper代理類使用字節(jié)碼技術(shù)動(dòng)態(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)