Java進(jìn)階-Dubbo-基礎(chǔ)

一、Dubbo簡(jiǎn)介

??總體架構(gòu):

image.png

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

image.png

??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ò)程

image.png

框架設(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;
}
創(chuàng)建拓展對(duì)象.png
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 ...");
    }
}
獲取自適應(yīng)拓展.png

四、服務(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ù)導(dǎo)出.png

五、服務(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;
}
服務(wù)引用.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容