Dubbo系列2-初始化(二)

spring容器啟動(dòng)的最后一步,就是實(shí)例化Bean;從上一節(jié)我們看到,dubbo中的service在注冊(cè)到spring容器中時(shí)是一個(gè)ServiceBean,這個(gè)ServiceBean可以理解成一個(gè)適配器,避免了dubbo中的ServcieConfig和spring直接集成。

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
    private static final long serialVersionUID = 213195494150089726L;

    private static transient ApplicationContext SPRING_CONTEXT;

    private final transient Service service;

    private transient ApplicationContext applicationContext;

    private transient String beanName;

    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            export();
        }
    }
    /** spring容器在實(shí)例化Bean的過程中會(huì)調(diào)用這個(gè)方法 */
    public void afterPropertiesSet() throws Exception {
        ...
        // 前面一大段都先不看,都是用來確保service發(fā)布的環(huán)境已經(jīng)初始化好,后面再回過來細(xì)看,核心是下面這個(gè)export()方法
        if (!isDelay()) {
            export();
        }
    }

}

export方法在ServiceBean的父類ServiceConfig中,而在ServiceConfig中,又依次調(diào)用方法export() -> doExport() -> doExportUrls():

private void doExportUrls() {
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
}

從這個(gè)方法可以看出來,一個(gè)service是同時(shí)支持多個(gè)協(xié)議的,在Service類上的標(biāo)注可以這么寫:@Service(protocol = {"dubbo","rest"}),繼續(xù)往下看:

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
// 前面的一大段還是忽略,主要是為service的export提供參數(shù)的,包括所有的方法名稱、重試次數(shù)、接口版本號(hào)等
...
    // 關(guān)鍵是這里,調(diào)用具體協(xié)議的export方法
    Exporter<?> exporter = protocol.export(wrapperInvoker);
...

先看看Dubbo協(xié)議是怎么export Service的,進(jìn)入DubboProtocal類的export方法:

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        exporterMap.put(key, exporter);

        //export an stub service for dispatching event
        Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
        Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
        if (isStubSupportEvent && !isCallbackservice) {
            String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
            if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
                if (logger.isWarnEnabled()) {
                    logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
                            "], has set stubproxy support event ,but no stub methods founded."));
                }
            } else {
                stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
            }
        }
        // 主要看這個(gè)方法
        openServer(url);
        optimizeSerialization(url);
        return exporter;
    }
...
private ExchangeServer createServer(URL url) {
        // send readonly event when server closes, it's enabled by default
        url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
        // enable heartbeat by default
        url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
        String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);

        if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
            throw new RpcException("Unsupported server type: " + str + ", url: " + url);

        url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
        ExchangeServer server;
        try {
            // 進(jìn)入交換層
            server = Exchangers.bind(url, requestHandler);
        } catch (RemotingException e) {
            throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
        }
        str = url.getParameter(Constants.CLIENT_KEY);
        if (str != null && str.length() > 0) {
            Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
            if (!supportedTypes.contains(str)) {
                throw new RpcException("Unsupported client type: " + str);
            }
        }
        return server;
    }

dubbo協(xié)議使用的是默認(rèn)的HeaderExchanger:

/**
 * DefaultMessenger
 *
 *
 */
public class HeaderExchanger implements Exchanger {

    public static final String NAME = "header";

    @Override
    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
    }

    @Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }

}

可以看到,在bind方法中通過調(diào)用Transport層的bind方法來創(chuàng)建ExchangerServer,來看看Transporters類的bind方法:

public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        }
        if (handlers == null || handlers.length == 0) {
            throw new IllegalArgumentException("handlers == null");
        }
        ChannelHandler handler;
        if (handlers.length == 1) {
            handler = handlers[0];
        } else {
            handler = new ChannelHandlerDispatcher(handlers);
        }
        return getTransporter().bind(url, handler);
    }

由于dubbo協(xié)議默認(rèn)使用netty來進(jìn)行遠(yuǎn)程調(diào)用,我們看看NettyTransporter:

public class NettyTransporter implements Transporter {

    public static final String NAME = "netty";

    @Override
    public Server bind(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyServer(url, listener);
    }

    @Override
    public Client connect(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyClient(url, listener);
    }

}

可以看到,最終就是啟動(dòng)了NettyServer。

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,644評(píng)論 19 139
  • dubbo服務(wù)發(fā)布 dubbo服務(wù)發(fā)布只需在spring.xml中如下配置即可:<dubbo:service in...
    阿飛的博客閱讀 1,735評(píng)論 6 10
  • dubbo暴露服務(wù)有兩種情況,一種是設(shè)置了延遲暴露(比如delay="5000"),另外一種是沒有設(shè)置延遲暴露或者...
    加大裝益達(dá)閱讀 21,413評(píng)論 5 36
  • 0 準(zhǔn)備 安裝注冊(cè)中心:Zookeeper、Dubbox自帶的dubbo-registry-simple;安裝Du...
    七寸知架構(gòu)閱讀 14,106評(píng)論 0 88
  • 兩年前,與她相識(shí), 腦中的定格是公主,心里的呼喚是嬌妻。 我活在幻想里。 一年前,她有所屬, 腦中的疼痛似刀絞,心...
    玉雕閱讀 279評(píng)論 0 0

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