dubbo系列--本地服務發佈源碼分析

先來看咱們的provider.xml的配置文件spring


這個文件的重要性確定重要,那麼這些標籤是怎麼來的呢?api

其實就是spring自定義標籤來的,在源碼中咱們能夠看到,緩存


繼續看spring.handlers文件中內容app


能夠看得出這個DubboNamespaceHandler應該很重要,最後能夠找出他的所在位置,同時還發現同目錄下還有DubboBeanDefinitionParser相似於spring中BeanDefinitionParser。DubboNamespaceHandler相似於spring中NamespaceHandler:ide


再進去看看裏面到底作了些什麼東東函數



能夠看到ui

DubboBeanDefinitionParser繼承spring的BeanDefinitionParser,DubboNamespaceHandlerSupport繼承spring的NamespaceHandlerSupport,NamespaceHandlerSupport繼承NamespaceHandler。由此能夠知道這個provider.xml配置文件的解析其實就是和spring同樣解析。url


 在這個spring目錄下咱們看到這兩個類spa


這兩個類很是重要:debug

ServiceBean服務端發佈入口

ReferenceBean客戶端發佈入口

先看看服務端的服務是怎麼發佈的


他是實現spring的這幾類來作的。因此仍是基於spring來作的

這個類中afterPropertiesSet()方法中。是否延遲加載


export()方法就是作了一些參數校驗


無論是否延遲加載都會走doExport()方法,doExport()方法也是作一些參數校驗
和配置項的校驗


而後調用doExportUrls()



就是在provider.xml中配置多個protocol


doExportUrlsFor1Protocol中
1:使用各類方法獲取本地ip
2:若是沒有配置端口則
final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();

 獲取默認端口dubbo默認20880


3:拼湊url

dubbo://192.168.11.1:20880/com.tian.dubbo.IGpHello?anyhost=true&application=hello-world-app&default.delay=10&delay=10&dubbo=2.5.6&generic=false&interface=com.tian.dubbo.IGpHello&methods=sayHello&pid=121964&side=provider×tamp=1529758790987

而後


debug到此


這裏有個Invoker對象爲




因此咱們能夠把Invoker對象理解爲服務的代理對象。

若是沒有配置註冊中心,

protocol

----->Protocol$Adaptive

---->ProtocolFilterWrapper(ProtocolListenerWrapper(DubboProtocol))。底層是基於netty協議去啓動一個nettyserver

} else {//若是沒有配置註冊中心
    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
    Exporter<?> exporter = protocol.export(invoker);//dubbo
    exporters.add(exporter);
}

Protocol extension = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(「registry」);


registry=com.alibaba.dubbo.registry.integration.RegistryProtocol

protocol=RegistryProtocol

RegistryProtocol的export方法源碼


 doLocalExport()本地發佈


對緩存進行雙重檢查鎖,若是有就直接返回,不然new一個

debug到此,相關屬性對應的值:


exporter相關屬性


此時相關值


上面


一樣根據

Protocol extension =ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(「dubbo」);

protocol=DubboProtocol.這裏並非得到一個單純的DubboProtocol擴展點,而是會經過Wrapper對Protocol進行裝飾,裝飾器分別爲: ProtocolFilterWrapper/ ProtocolListenerWrapper;兩個裝飾類的源碼爲如下:


ProtocolFilterWrapper

這個類很是重要,dubbo機制裏面日誌記錄、超時等等功能都是在這一部分實現的

這個類有3個特色,

第一它有一個參數爲Protocol protocol的構造函數;

第二,它實現了Protocol接口;

第三,它使用責任鏈模式,對export和refer函數進行了封裝;部分代碼以下,上面的源碼中ProtocolFilterWrapper有個buildInvokderChain()方法

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
public void destroy() {
    protocol.destroy();
}

//buildInvokerChain函數:它讀取全部的filter類,利用這些類封裝invoker
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);//自動激活擴展點,根據條件獲取當前擴展可自動激活的實現
    if (filters.size() > 0) {
        for (int i = filters.size() - 1; i >= 0; i --) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }
                public URL getUrl() {
                    return invoker.getUrl();
                }
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }
                public void destroy() {
                    invoker.destroy();
                }
                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}

 

咱們看以下文件:

 /dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Filter

其實就是對Invoker,經過以下的Filter組裝成一個責任鏈

echo=com.alibaba.dubbo.rpc.filter.EchoFilter
generic=com.alibaba.dubbo.rpc.filter.GenericFilter
genericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFilter
token=com.alibaba.dubbo.rpc.filter.TokenFilter
accesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilter
activelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilter
classloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFilter
context=com.alibaba.dubbo.rpc.filter.ContextFilter
consumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilter
exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter
executelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter
deprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFilter
compatible=com.alibaba.dubbo.rpc.filter.CompatibleFilter
timeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter

這其中涉及到不少功能,包括權限驗證、異常、超時等等,固然能夠預計計算調用時間等等應該也是在這其中的某個類實現的;這裏其實就是dubbo中AOP

這裏咱們能夠看到export和refer過程都會被filter過濾


ProtocolListenerWrapper

在這裏咱們能夠看到export和refer分別對應了不一樣的Wrapper;export是對應的ListenerExporterWrapper。這塊暫時先不去分析,由於這個地方並無提供實現類。

debug到此


exporterMap




createServer方法()


Exchangers.bind()方法


這裏使用的是getExchange(url)=默認自適應擴展類HeaderExchanger


這裏先去Transporters.bind()方法,


getTransporter().bind(url, handler);


這裏的自適應擴展類就是默認的netty的


構造一個NettyServer


繼續調用父類的方法


這個open()方法在這個父類裏並無實現,而是採用模板方法模式,由各自實現類本身去實現


到此本地發佈已經結束。

相關文章
相關標籤/搜索