一、Dubbo簡(jiǎn)介
??總體架構(gòu):

??分層結(jié)構(gòu):

??Dubbo核心領(lǐng)域模型:
- Protocol是服務(wù)域,它是Invoker暴露和引用的主功能入口,它負(fù)責(zé)Invoker的生命周期管理;
- Invoker是實(shí)體域,它是Dubbo的核心模型,其它模型都向它靠擾,或轉(zhuǎn)換成它,它代表一個(gè)可執(zhí)行體,可向它發(fā)起invoke調(diào)用,它有可能是一個(gè)本地的實(shí)現(xiàn),也可能是一個(gè)遠(yuǎn)程的實(shí)現(xiàn),也可能一個(gè)集群實(shí)現(xiàn);
- Invocation是會(huì)話域,它持有調(diào)用過(guò)程中的變量,比如方法名,參數(shù)等。
??基本設(shè)計(jì)原則:
- 采用Microkernel+Plugin模式,Microkernel只負(fù)責(zé)組裝Plugin,Dubbo自身的功能也是通過(guò)擴(kuò)展點(diǎn)實(shí)現(xiàn)的,也就是Dubbo的所有功能點(diǎn)都可被用戶自定義擴(kuò)展所替換;
- 采用URL作為配置信息的統(tǒng)一格式,所有擴(kuò)展點(diǎn)都通過(guò)傳遞URL攜帶配置信息。
??SPI(Service Provider Interface),是JDK內(nèi)置的一個(gè)服務(wù)發(fā)現(xiàn)機(jī)制,它使得接口和具體實(shí)現(xiàn)完全解耦。我們只聲明接口,具體的實(shí)現(xiàn)類在配置中選擇。
??服務(wù)暴露/消費(fèi)者調(diào)用過(guò)程:

框架設(shè)計(jì):https://dubbo.apache.org/zh/docs/v2.7/dev/design/
二、Dubbo SPI
??通過(guò)ExtensionLoader的getExtensionLoader方法獲取一個(gè)ExtensionLoader實(shí)例,然后再通過(guò)ExtensionLoader的getExtension方法獲取拓展類對(duì)象。
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
} else if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
} else if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
} else {
ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
}
return loader;
}
}
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
// 獲取默認(rèn)的拓展實(shí)現(xiàn)類
return getDefaultExtension();
}
// Holder,顧名思義,用于持有目標(biāo)對(duì)象
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
// 雙重檢查
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 創(chuàng)建拓展實(shí)例
instance = createExtension(name);
// 設(shè)置實(shí)例到 holder 中
holder.set(instance);
}
}
}
return (T) instance;
}

private T injectExtension(T instance) {
try {
if (objectFactory != null) {
// 遍歷目標(biāo)類的所有方法
for (Method method : instance.getClass().getMethods()) {
// 檢測(cè)方法是否以 set 開(kāi)頭,且方法僅有一個(gè)參數(shù),且方法訪問(wèn)級(jí)別為 public
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
// 獲取 setter 方法參數(shù)類型
Class<?> pt = method.getParameterTypes()[0];
try {
// 獲取屬性名,比如 setName 方法對(duì)應(yīng)屬性名 name
String property = method.getName().length() > 3 ?
method.getName().substring(3, 4).toLowerCase() +
method.getName().substring(4) : "";
// 從 ObjectFactory 中獲取依賴對(duì)象
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
// 通過(guò)反射調(diào)用 setter 方法設(shè)置依賴
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method...");
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
三、SPI自適應(yīng)擴(kuò)展
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
String[] value() default {};
}
??當(dāng)Adaptive注解在類上時(shí),Dubbo不會(huì)為該類生成代理類。注解在方法(接口方法)上時(shí),Dubbo則會(huì)為該方法生成代理邏輯。Adaptive注解在類上的情況很少,在Dubbo中,僅有兩個(gè)類被 Adaptive注解了,分別是AdaptiveCompiler和AdaptiveExtensionFactory。此種情況,表示拓展的加載邏輯由人工編碼完成。更多時(shí)候,Adaptive是注解在接口方法上的,表示拓展的加載邏輯需由框架自動(dòng)生成。
public T getAdaptiveExtension() {
// 從緩存中獲取自適應(yīng)拓展
Object instance = cachedAdaptiveInstance.get();
if (instance == null) { // 緩存未命中
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 創(chuàng)建自適應(yīng)拓展
instance = createAdaptiveExtension();
// 設(shè)置自適應(yīng)拓展到緩存中
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: ...");
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: ...");
}
}
return (T) instance;
}
private T createAdaptiveExtension() {
try {
// 獲取自適應(yīng)拓展類,并通過(guò)反射實(shí)例化
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension ...");
}
}

四、服務(wù)導(dǎo)出
??服務(wù)導(dǎo)出的入口方法是ServiceBean的onApplicationEvent。onApplicationEvent是一個(gè)事件響應(yīng)方法,該方法會(huì)在收到Spring上下文刷新事件后執(zhí)行服務(wù)導(dǎo)出操作。
public void onApplicationEvent(ContextRefreshedEvent event) {
// 是否有延遲導(dǎo)出 && 是否已導(dǎo)出 && 是不是已被取消導(dǎo)出
if (isDelay() && !isExported() && !isUnexported()) {
// 導(dǎo)出服務(wù)
export();
}
}
??ServiceBean是Dubbo與Spring框架進(jìn)行整合的關(guān)鍵,可以看做是兩個(gè)框架之間的橋梁。具有同樣作用的類還有ReferenceBean。
??采用URL作為配置信息的統(tǒng)一格式,所有擴(kuò)展點(diǎn)都通過(guò)傳遞URL攜帶配置信息。
public synchronized void export() {
if (provider != null) {
// 獲取 export 和 delay 配置
if (export == null) {
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
// 如果 export 為 false,則不導(dǎo)出服務(wù)
if (export != null && !export) {
return;
}
// delay > 0,延時(shí)導(dǎo)出服務(wù)
if (delay != null && delay > 0) {
delayExportExecutor.schedule(new Runnable() {
@Override
public void run() {
doExport();
}
}, delay, TimeUnit.MILLISECONDS);
// 立即導(dǎo)出服務(wù)
} else {
doExport();
}
}
private void doExportUrls() {
// 加載注冊(cè)中心鏈接
List<URL> registryURLs = loadRegistries(true);
// 遍歷 protocols,并在每個(gè)協(xié)議下導(dǎo)出服務(wù)
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
??Invoker 是實(shí)體域,它是Dubbo的核心模型,其它模型都向它靠擾,或轉(zhuǎn)換成它,它代表一個(gè)可執(zhí)行體,可向它發(fā)起invoke調(diào)用,它有可能是一個(gè)本地的實(shí)現(xiàn),也可能是一個(gè)遠(yuǎn)程的實(shí)現(xiàn),也可能一個(gè)集群實(shí)現(xiàn)。
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// 為目標(biāo)類創(chuàng)建 Wrapper
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
// 創(chuàng)建匿名 Invoker 類對(duì)象,并實(shí)現(xiàn) doInvoke 方法。
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
// 調(diào)用 Wrapper 的 invokeMethod 方法,invokeMethod 最終會(huì)調(diào)用目標(biāo)方法
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}

五、服務(wù)引用
??Dubbo 服務(wù)引用的時(shí)機(jī)有兩個(gè):
- 在 Spring容器調(diào)用ReferenceBean的afterPropertiesSet 方法時(shí)引用服務(wù)(餓漢式)
- 在ReferenceBean對(duì)應(yīng)的服務(wù)被注入到其他類中時(shí)引用(懶漢式,默認(rèn))
??先進(jìn)行配置檢查與收集工作。接著根據(jù)收集到的信息決定服務(wù)用的方式,有三種:
- 第一種是引用本地 (JVM) 服務(wù)
- 第二是通過(guò)直連方式引用遠(yuǎn)程服務(wù)
- 第三是通過(guò)注冊(cè)中心引用遠(yuǎn)程服務(wù)
??服務(wù)引用的入口方法為ReferenceBean的getObject 方法,該方法定義在Spring的FactoryBean接口中,ReferenceBean實(shí)現(xiàn)了這個(gè)方法。
public Object getObject() throws Exception {
return get();
}
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("Already destroyed!");
}
// 檢測(cè) ref 是否為空,為空則通過(guò) init 方法創(chuàng)建
if (ref == null) {
// init 方法主要用于處理配置,以及調(diào)用 createProxy 生成代理類
init();
}
return ref;
}
??Invoker是Dubbo的核心模型,代表一個(gè)可執(zhí)行體。在服務(wù)提供方,Invoker用于調(diào)用服務(wù)提供類。在服務(wù)消費(fèi)方,Invoker用于執(zhí)行遠(yuǎn)程調(diào)用。
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
optimizeSerialization(url);
// 創(chuàng)建 DubboInvoker
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
invokers.add(invoker);
return invoker;
}
