☆聊聊Dubbo(八):核心源碼-容器啟動/停止

1 介紹

服務(wù)容器是 一個 standalone 的啟動程序,因?yàn)楹笈_服務(wù)不需要 Tomcat 或 JBoss 等 Web 容器的功能,如果硬要用 Web 容器去加載服務(wù)提供方,增加復(fù)雜性,也浪費(fèi)資源敬辣。

服務(wù)容器 只是一個簡單的 Main 方法雪标,并加載一個簡單的 Spring 容器,用于暴露服務(wù)溉跃。

服務(wù)容器的加載內(nèi)容可以擴(kuò)展村刨,內(nèi)置了 spring, jetty, log4j, logback等加載,可通過容器擴(kuò)展點(diǎn)進(jìn)行擴(kuò)展撰茎。配置配在 java 命令的 -Ddubbo.container 參數(shù)或者 dubbo.properties 中嵌牺。

2 容器類型

2.1 Spring Container

  1. 自動加載 META-INF/spring 目錄下的所有 Spring 配置。
  2. 配置 spring 配置加載位置(配在java命令-D參數(shù)或者dubbo.properties中):
    dubbo.container=log4j,spring
    dubbo.spring.config=classpath*:META-INF/spring/*.xml
    

2.2 Jetty Container

  1. 啟動一個內(nèi)嵌 Jetty龄糊,用于匯報狀態(tài)逆粹。
  2. 配置:
    dubbo.jetty.port=8080:配置 jetty 啟動端口
    dubbo.jetty.directory=/foo/bar:配置可通過 jetty 直接訪問的目錄,用于存放靜態(tài)文件
    dubbo.jetty.page=log,status,system:配置顯示的頁面炫惩,缺省加載所有頁面
    

2.3 Log4j Container

  1. 自動配置 log4j 的配置僻弹,在多進(jìn)程啟動時,自動給日志文件按進(jìn)程分目錄他嚷。
  2. 配置:
    dubbo.log4j.file=/foo/bar.log:配置日志文件路徑
    dubbo.log4j.level=WARN:配置日志級別
    dubbo.log4j.subdirectory=20880:配置日志子目錄蹋绽,用于多進(jìn)程啟動,避免沖突
    

3 容器啟動

com.alibaba.dubbo.container.Main 是服務(wù)啟動的主類筋蓖,缺省只加載 spring:

java com.alibaba.dubbo.container.Main

通過 main 函數(shù)參數(shù)傳入要加載的容器:

java com.alibaba.dubbo.container.Main spring jetty log4j

通過 JVM 啟動參數(shù)傳入要加載的容器:

java com.alibaba.dubbo.container.Main -Ddubbo.container=spring,jetty,log4j

通過 classpath 下的 dubbo.properties 配置傳入要加載的容器:

dubbo.container=spring,jetty,log4j

3.1 源碼分析

com.alibaba.dubbo.container.Main卸耘,源碼如下:

public class Main {
    public static final String CONTAINER_KEY = "dubbo.container";
    public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";

    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);

    private static volatile boolean running = true;
    /**
     * 啟動發(fā)布
     * @param args
     */
    public static void main(String[] args) {
        try {
            // 開始判斷main函數(shù)的傳入?yún)?shù),在args參數(shù)為空的情況下粘咖,從部署環(huán)境中取得dubbo.container屬性蚣抗,
            if (args == null || args.length == 0) {
                // 讀取dubbo.properties中dubbo.container屬性值,為空時通過loader.getDefaultExtensionName()獲取默認(rèn)值
                String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
                args = Constants.COMMA_SPLIT_PATTERN.split(config);
            }

            final List<Container> containers = new ArrayList<Container>();
            // 遍歷獲取指定名稱的擴(kuò)展加入到列表中
            for (int i = 0; i < args.length; i ++) {
                containers.add(loader.getExtension(args[i]));
            }
            logger.info("Use container type(" + Arrays.toString(args) + ") to run dubbo serivce.");

            // 添加jvm關(guān)閉的鉤子瓮下,用來在jvm關(guān)閉時關(guān)閉容器
            if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    public void run() {
                        for (Container container : containers) {
                            try {
                                container.stop();
                                logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
                            } catch (Throwable t) {
                                logger.error(t.getMessage(), t);
                            }
                            synchronized (Main.class) {
                                running = false;
                                Main.class.notify();
                            }
                        }
                    }
                });
            }

            // 啟動服務(wù)
            for (Container container : containers) {
                container.start();
                logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
            }
            System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Dubbo service server started!");
        } catch (RuntimeException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            System.exit(1);
        }
        synchronized (Main.class) {
            while (running) {
                try {
                    Main.class.wait();
                } catch (Throwable e) {
                }
            }
        }
    }
}
Container SPI 擴(kuò)展配置
  1. 如上圖翰铡,依據(jù)Dubbo SPI機(jī)制,通過ExtensionLoader.getExtensionLoader(Container.class)讽坏,獲取ExtensionLoader實(shí)例:

    private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);
    
  2. 通過loader.getExtension(args[i])两蟀,獲取擴(kuò)展類實(shí)例:

    final List<Container> containers = new ArrayList<Container>();
    for (int i = 0; i < args.length; i++) {
        containers.add(loader.getExtension(args[i]));
    }
    
  3. 遍歷containers,啟動容器:

    for (Container container : containers) {
        container.start();
        logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
    }
    

看到這里我們發(fā)現(xiàn)程序一旦啟動就一直在運(yùn)行震缭,但是我們還是沒有到如何加載dubbo spring配置文件,不要著急战虏,我們繼續(xù)看start和stop方法:

public class SpringContainer implements Container {
    private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class);
    public static final String SPRING_CONFIG = "dubbo.spring.config";

    public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml";
    static ClassPathXmlApplicationContext context;

    public static ClassPathXmlApplicationContext getContext() {
        return context;
    }
    public void start() {
        String configPath = ConfigUtils.getProperty(SPRING_CONFIG);
        if (configPath == null || configPath.length() == 0) {
            configPath = DEFAULT_SPRING_CONFIG;
        }
        context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
        context.start();
    }
    public void stop() {
        try {
            if (context != null) {
                context.stop();
                context.close();
                context = null;
            }
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }
    }
}

4 優(yōu)雅停機(jī)

Dubbo是通過JDK的 ShutdownHook 來完成優(yōu)雅停機(jī)的拣宰,所以如果用戶使用 kill -9 PID 等強(qiáng)制關(guān)閉指令,是不會執(zhí)行優(yōu)雅停機(jī)的,只有通過 kill PID 時烦感,才會執(zhí)行巡社。

4.1 源碼分析

服務(wù)容器通過Runtime.getRuntime().addShutdownHook(new Thread())添加停機(jī)時的回調(diào)鉤子,源碼如下:

if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            for (Container container : containers) {
                try {
                    container.stop();
                    logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
                } catch (Throwable t) {
                    logger.error(t.getMessage(), t);
                }
                try {
                    LOCK.lock();
                    STOP.signal();
                } finally {
                    LOCK.unlock();
                }
            }
        }
    });
}

5 容器擴(kuò)展

服務(wù)容器擴(kuò)展手趣,用于自定義加載內(nèi)容晌该。

5.1 擴(kuò)展示例

Maven 項(xiàng)目結(jié)構(gòu):

src
 |-main
    |-java
        |-com
            |-xxx
                |-XxxContainer.java (實(shí)現(xiàn)Container接口)
    |-resources
        |-META-INF
            |-dubbo
                |-com.alibaba.dubbo.container.Container (純文本文件肥荔,內(nèi)容為:xxx=com.xxx.XxxContainer)

XxxContainer.java:

package com.xxx;

import com.alibaba.dubbo.container.Container;

public class XxxContainer implements Container {
    public Status start() {
        // ...
    }
    public Status stop() {
        // ...
    }
}

META-INF/dubbo/com.alibaba.dubbo.container.Container:

xxx=com.xxx.XxxContainer
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市朝群,隨后出現(xiàn)的幾起案子燕耿,更是在濱河造成了極大的恐慌,老刑警劉巖姜胖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件誉帅,死亡現(xiàn)場離奇詭異,居然都是意外死亡右莱,警方通過查閱死者的電腦和手機(jī)蚜锨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慢蜓,“玉大人亚再,你說我怎么就攤上這事〕柯眨” “怎么了氛悬?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凄诞。 經(jīng)常有香客問我圆雁,道長,這世上最難降的妖魔是什么帆谍? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任伪朽,我火速辦了婚禮,結(jié)果婚禮上汛蝙,老公的妹妹穿的比我還像新娘烈涮。我一直安慰自己,他們只是感情好窖剑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布坚洽。 她就那樣靜靜地躺著,像睡著了一般西土。 火紅的嫁衣襯著肌膚如雪讶舰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天需了,我揣著相機(jī)與錄音跳昼,去河邊找鬼。 笑死肋乍,一個胖子當(dāng)著我的面吹牛鹅颊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播墓造,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼堪伍,長吁一口氣:“原來是場噩夢啊……” “哼锚烦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帝雇,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤涮俄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摊求,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禽拔,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年室叉,在試婚紗的時候發(fā)現(xiàn)自己被綠了睹栖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡茧痕,死狀恐怖野来,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踪旷,我是刑警寧澤曼氛,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站令野,受9級特大地震影響舀患,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜气破,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一聊浅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧现使,春花似錦低匙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至售碳,卻和暖如春强重,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贸人。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工间景, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灸姊。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像秉溉,于是被迫代替她去往敵國和親力惯。 傳聞我的和親對象是個殘疾皇子碗誉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 參考 屬于在這篇Dubbo擴(kuò)展點(diǎn)加載基礎(chǔ)上的展開學(xué)習(xí)。但原文有點(diǎn)小問題(Container啟動那里)父晶,所以本文直接...
    靜態(tài)變量閱讀 4,493評論 0 9
  • 一哮缺、Dubbo簡介 Dubbo是Alibaba開源的分布式服務(wù)框架,它按照分層的方式來架構(gòu)甲喝,使用這種方式可以使各層...
    落地生涯閱讀 2,217評論 0 9
  • 內(nèi)容簡介此篇文章是介紹Dubbo以及它的簡單使用尝苇,會列舉運(yùn)用spring boot + dubbo搭建項(xiàng)目運(yùn)用du...
    Little_Dragon_閱讀 837評論 0 3
  • 摘要:在Dubbo的官網(wǎng)上,Dubbo描述自己是一個高性能的RPC框架埠胖。今天我想聊聊Dubbo的另一個很棒的特性,...
    貓耳呀閱讀 1,841評論 0 15
  • 八月一到秋風(fēng)吹不盡 總是懷秋情 八月一來秋雨綿綿不絕斷 秋天來了 鳥兒有蟲吃 花兒齊開放 魚兒水中游 喜鵲枝頭喳喳...
    王密亮閱讀 278評論 1 2