国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

渣渣的 ElasticSearch 源碼解析 —— 啟動(dòng)流程(上)

AZmake / 3123人閱讀

摘要:總結(jié)這篇文章主要先把大概啟動(dòng)流程串通,因?yàn)槠^多所以拆開(kāi)成兩篇,先不扣細(xì)節(jié)了,后面流程啟動(dòng)文章寫(xiě)完后我們?cè)賳我坏目奂?xì)節(jié)。

關(guān)注我

轉(zhuǎn)載請(qǐng)務(wù)必注明原創(chuàng)地址為:http://www.54tianzhisheng.cn/2018/08/11/es-code02/

前提

上篇文章寫(xiě)了 ElasticSearch 源碼解析 —— 環(huán)境搭建 ,其中里面說(shuō)了啟動(dòng) 打開(kāi) server 模塊下的 Elasticsearch 類(lèi):org.elasticsearch.bootstrap.Elasticsearch,運(yùn)行里面的 main 函數(shù)就可以啟動(dòng) ElasticSearch 了,這篇文章講講啟動(dòng)流程,因?yàn)槠鶗?huì)很多,所以分了兩篇來(lái)寫(xiě)。

啟動(dòng)流程 main 方法入口

可以看到入口其實(shí)是一個(gè) main 方法,方法里面先是檢查權(quán)限,然后是一個(gè)錯(cuò)誤日志監(jiān)聽(tīng)器(確保在日志配置之前狀態(tài)日志沒(méi)有出現(xiàn) error),然后是 Elasticsearch 對(duì)象的創(chuàng)建,然后調(diào)用了靜態(tài)方法 main 方法(18 行),并把創(chuàng)建的對(duì)象和參數(shù)以及 Terminal 默認(rèn)值傳進(jìn)去。靜態(tài)的 main 方法里面調(diào)用 elasticsearch.main 方法。

public static void main(final String[] args) throws Exception {         //1、入口
    // we want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the
    // presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy)
    System.setSecurityManager(new SecurityManager() {
        @Override
        public void checkPermission(Permission perm) {
            // grant all permissions so that we can later set the security manager to the one that we want
        }
    });
    LogConfigurator.registerErrorListener();                            //
    final Elasticsearch elasticsearch = new Elasticsearch();
    int status = main(args, elasticsearch, Terminal.DEFAULT); //2、調(diào)用Elasticsearch.main方法
    if (status != ExitCodes.OK) {
        exit(status);
    }
}

static int main(final String[] args, final Elasticsearch elasticsearch, final Terminal terminal) throws Exception {
    return elasticsearch.main(args, terminal);  //3、command main
}

因?yàn)?Elasticsearch 類(lèi)是繼承了 EnvironmentAwareCommand 類(lèi),EnvironmentAwareCommand 類(lèi)繼承了 Command 類(lèi),但是 Elasticsearch 類(lèi)并沒(méi)有重寫(xiě) main 方法,所以上面調(diào)用的 elasticsearch.main 其實(shí)是調(diào)用了 Command 的 main 方法,代碼如下:

/** Parses options for this command from args and executes it. */
public final int main(String[] args, Terminal terminal) throws Exception {
    if (addShutdownHook()) {                                                //利用Runtime.getRuntime().addShutdownHook方法加入一個(gè)Hook,在程序退出時(shí)觸發(fā)該Hook
        shutdownHookThread = new Thread(() -> {
            try {
                this.close();
            } catch (final IOException e) {
                try (
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new PrintWriter(sw)) {
                    e.printStackTrace(pw);
                    terminal.println(sw.toString());
                } catch (final IOException impossible) {
                    // StringWriter#close declares a checked IOException from the Closeable interface but the Javadocs for StringWriter
                    // say that an exception here is impossible
                    throw new AssertionError(impossible);
                }
            }
        });
        Runtime.getRuntime().addShutdownHook(shutdownHookThread);
    }

    beforeMain.run();

    try {
        mainWithoutErrorHandling(args, terminal);//4、mainWithoutErrorHandling
    } catch (OptionException e) {
        printHelp(terminal);
        terminal.println(Terminal.Verbosity.SILENT, "ERROR: " + e.getMessage());
        return ExitCodes.USAGE;
    } catch (UserException e) {
        if (e.exitCode == ExitCodes.USAGE) {
            printHelp(terminal);
        }
        terminal.println(Terminal.Verbosity.SILENT, "ERROR: " + e.getMessage());
        return e.exitCode;
    }
    return ExitCodes.OK;
}

上面代碼一開(kāi)始利用一個(gè)勾子函數(shù),在程序退出時(shí)觸發(fā)該 Hook,該方法主要代碼是 mainWithoutErrorHandling() 方法,然后下面的是 catch 住方法拋出的異常,方法代碼如下:

/*** Executes the command, but all errors are thrown. */
void mainWithoutErrorHandling(String[] args, Terminal terminal) throws Exception {
    final OptionSet options = parser.parse(args);
    if (options.has(helpOption)) {
        printHelp(terminal);
        return;
    }
    if (options.has(silentOption)) {
        terminal.setVerbosity(Terminal.Verbosity.SILENT);
    } else if (options.has(verboseOption)) {
        terminal.setVerbosity(Terminal.Verbosity.VERBOSE);
    } else {
        terminal.setVerbosity(Terminal.Verbosity.NORMAL);
    }
    execute(terminal, options);//5、執(zhí)行 EnvironmentAwareCommand 中的 execute(),(重寫(xiě)了command里面抽象的execute方法)
}

上面的代碼從 3 ~ 14 行是解析傳進(jìn)來(lái)的參數(shù)并配置 terminal,重要的 execute() 方法,執(zhí)行的是 EnvironmentAwareCommand 中的 execute() (重寫(xiě)了 Command 類(lèi)里面的抽象 execute 方法),從上面那個(gè)繼承圖可以看到 EnvironmentAwareCommand 繼承了 Command,重寫(xiě)的 execute 方法代碼如下:

@Override
protected void execute(Terminal terminal, OptionSet options) throws Exception {
    final Map settings = new HashMap<>();
    for (final KeyValuePair kvp : settingOption.values(options)) {
        if (kvp.value.isEmpty()) {
            throw new UserException(ExitCodes.USAGE, "setting [" + kvp.key + "] must not be empty");
        }
        if (settings.containsKey(kvp.key)) {
            final String message = String.format(
                Locale.ROOT, "setting [%s] already set, saw [%s] and [%s]",
                kvp.key, settings.get(kvp.key), kvp.value);
            throw new UserException(ExitCodes.USAGE, message);
        }
        settings.put(kvp.key, kvp.value);
    }
    //6、根據(jù)我們ide配置的 vm options 進(jìn)行設(shè)置path.data、path.home、path.logs
    putSystemPropertyIfSettingIsMissing(settings, "path.data", "es.path.data");
    putSystemPropertyIfSettingIsMissing(settings, "path.home", "es.path.home");
    putSystemPropertyIfSettingIsMissing(settings, "path.logs", "es.path.logs");

    execute(terminal, options, createEnv(terminal, settings));//7、先調(diào)用 createEnv 創(chuàng)建環(huán)境
    //9、執(zhí)行elasticsearch的execute方法,elasticsearch中重寫(xiě)了EnvironmentAwareCommand中的抽象execute方法
}

方法前面是根據(jù)傳參去判斷配置的,如果配置為空,就會(huì)直接跳到執(zhí)行 putSystemPropertyIfSettingIsMissing 方法,這里會(huì)配置三個(gè)屬性:path.data、path.home、path.logs 設(shè)置 es 的 data、home、logs 目錄,它這里是根據(jù)我們 ide 配置的 vm options 進(jìn)行設(shè)置的,這也是為什么我們上篇文章說(shuō)的配置信息,如果不配置的話就會(huì)直接報(bào)錯(cuò)。下面看看 putSystemPropertyIfSettingIsMissing 方法代碼里面怎么做到的:

/** Ensure the given setting exists, reading it from system properties if not already set. */
private static void putSystemPropertyIfSettingIsMissing(final Map settings, final String setting, final String key) {
    final String value = System.getProperty(key);//獲取key(es.path.data)找系統(tǒng)設(shè)置
    if (value != null) {
        if (settings.containsKey(setting)) {
            final String message =
                String.format(
                Locale.ROOT,
                "duplicate setting [%s] found via command-line [%s] and system property [%s]",
                setting, settings.get(setting), value);
            throw new IllegalArgumentException(message);
        } else {
            settings.put(setting, value);
        }
    }
}

執(zhí)行這三個(gè)方法后:

跳出此方法,繼續(xù)看會(huì)發(fā)現(xiàn) execute 方法調(diào)用了方法,

 execute(terminal, options, createEnv(terminal, settings));

這里我們先看看 createEnv(terminal, settings) 方法:

protected Environment createEnv(final Terminal terminal, final Map settings) throws UserException {
    final String esPathConf = System.getProperty("es.path.conf");//8、讀取我們 vm options 中配置的 es.path.conf
    if (esPathConf == null) {
        throw new UserException(ExitCodes.CONFIG, "the system property [es.path.conf] must be set");
    }
    return InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings, getConfigPath(esPathConf));  //8、準(zhǔn)備環(huán)境 prepareEnvironment
}

讀取我們 ide vm options 中配置的 es.path.conf,同上篇文章也講了這個(gè)一定要配置的,因?yàn)?es 啟動(dòng)的時(shí)候會(huì)加載我們的配置和一些插件。這里繼續(xù)看下上面代碼第 6 行的 prepareEnvironment 方法:

public static Environment prepareEnvironment(Settings input, Terminal terminal, Map properties, Path configPath) {
    // just create enough settings to build the environment, to get the config dir
    Settings.Builder output = Settings.builder();
    initializeSettings(output, input, properties);
    Environment environment = new Environment(output.build(), configPath);

    //查看 es.path.conf 目錄下的配置文件是不是 yml 格式的,如果不是則拋出一個(gè)異常
    if (Files.exists(environment.configFile().resolve("elasticsearch.yaml"))) {
        throw new SettingsException("elasticsearch.yaml was deprecated in 5.5.0 and must be renamed to elasticsearch.yml");
    }

    if (Files.exists(environment.configFile().resolve("elasticsearch.json"))) {
        throw new SettingsException("elasticsearch.json was deprecated in 5.5.0 and must be converted to elasticsearch.yml");
    }

    output = Settings.builder(); // start with a fresh output
    Path path = environment.configFile().resolve("elasticsearch.yml");
    if (Files.exists(path)) {
        try {
            output.loadFromPath(path);  //加載文件并讀取配置文件內(nèi)容
        } catch (IOException e) {
            throw new SettingsException("Failed to load settings from " + path.toString(), e);
        }
    }

    // re-initialize settings now that the config file has been loaded
    initializeSettings(output, input, properties);          //再一次初始化設(shè)置
    finalizeSettings(output, terminal);

    environment = new Environment(output.build(), configPath);

    // we put back the path.logs so we can use it in the logging configuration file
    output.put(Environment.PATH_LOGS_SETTING.getKey(), environment.logsFile().toAbsolutePath().normalize().toString());
    return new Environment(output.build(), configPath);
}

準(zhǔn)備的環(huán)境如上圖,通過(guò)構(gòu)建的環(huán)境查看配置文件 elasticsearch.yml 是不是以 yml 結(jié)尾,如果是 yaml 或者 json 結(jié)尾的則拋出異常(在 5.5.0 版本其他兩種格式過(guò)期了,只能使用 yml 格式),然后加載該配置文件并讀取里面的內(nèi)容(KV結(jié)構(gòu))。

跳出 createEnv 方法,我們繼續(xù)看 execute 方法吧。

EnvironmentAwareCommand 類(lèi)的 execute 方法代碼如下:

protected abstract void execute(Terminal terminal, OptionSet options, Environment env) throws Exception;

這是個(gè)抽象方法,那么它的實(shí)現(xiàn)方法在 Elasticsearch 類(lèi)中,代碼如下:

@Override
protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException {
    if (options.nonOptionArguments().isEmpty() == false) {
        throw new UserException(ExitCodes.USAGE, "Positional arguments not allowed, found " + options.nonOptionArguments());
    }
    if (options.has(versionOption)) {
        final String versionOutput = String.format(
            Locale.ROOT,
            "Version: %s, Build: %s/%s/%s/%s, JVM: %s",
            Version.displayVersion(Version.CURRENT, Build.CURRENT.isSnapshot()),
            Build.CURRENT.flavor().displayName(),
            Build.CURRENT.type().displayName(),
            Build.CURRENT.shortHash(),
            Build.CURRENT.date(),
            JvmInfo.jvmInfo().version());
        terminal.println(versionOutput);
        return;
    }

    final boolean daemonize = options.has(daemonizeOption);
    final Path pidFile = pidfileOption.value(options);
    final boolean quiet = options.has(quietOption);

    // a misconfigured java.io.tmpdir can cause hard-to-diagnose problems later, so reject it immediately
    try {
        env.validateTmpFile();
    } catch (IOException e) {
        throw new UserException(ExitCodes.CONFIG, e.getMessage());
    }
    try {
        init(daemonize, pidFile, quiet, env);    //10、初始化
    } catch (NodeValidationException e) {
        throw new UserException(ExitCodes.CONFIG, e.getMessage());
    }
}

上面代碼里主要還是看看 init(daemonize, pidFile, quiet, env); 初始化方法吧。

void init(final boolean daemonize, final Path pidFile, final boolean quiet, Environment initialEnv)
    throws NodeValidationException, UserException {
    try {
        Bootstrap.init(!daemonize, pidFile, quiet, initialEnv); //11、執(zhí)行 Bootstrap 中的 init 方法
    } catch (BootstrapException | RuntimeException e) {
        // format exceptions to the console in a special way
        // to avoid 2MB stacktraces from guice, etc.
        throw new StartupException(e);
    }
}
init 方法

Bootstrap 中的靜態(tài) init 方法如下:

static void init(
    final boolean foreground,
    final Path pidFile,
    final boolean quiet,
    final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException {
    // force the class initializer for BootstrapInfo to run before
    // the security manager is installed
    BootstrapInfo.init();

    INSTANCE = new Bootstrap();   //12、創(chuàng)建一個(gè) Bootstrap 實(shí)例

    final SecureSettings keystore = loadSecureSettings(initialEnv);//如果注冊(cè)了安全模塊則將相關(guān)配置加載進(jìn)來(lái)
    final Environment environment = createEnvironment(foreground, pidFile, keystore, initialEnv.settings(), initialEnv.configFile());   //干之前干過(guò)的事情
    try {
        LogConfigurator.configure(environment);   //13、log 配置環(huán)境
    } catch (IOException e) {
        throw new BootstrapException(e);
    }
    if (environment.pidFile() != null) {
        try {
            PidFile.create(environment.pidFile(), true);
        } catch (IOException e) {
            throw new BootstrapException(e);
        }
    }

    final boolean closeStandardStreams = (foreground == false) || quiet;
    try {
        if (closeStandardStreams) {
            final Logger rootLogger = ESLoggerFactory.getRootLogger();
            final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class);
            if (maybeConsoleAppender != null) {
                Loggers.removeAppender(rootLogger, maybeConsoleAppender);
            }
            closeSystOut();
        }

        // fail if somebody replaced the lucene jars
        checkLucene();             //14、檢查L(zhǎng)ucene版本

// install the default uncaught exception handler; must be done before security is initialized as we do not want to grant the runtime permission setDefaultUncaughtExceptionHandler
        Thread.setDefaultUncaughtExceptionHandler(
            new ElasticsearchUncaughtExceptionHandler(() -> Node.NODE_NAME_SETTING.get(environment.settings())));

        INSTANCE.setup(true, environment);      //15、調(diào)用 setup 方法

        try {
            // any secure settings must be read during node construction
            IOUtils.close(keystore);
        } catch (IOException e) {
            throw new BootstrapException(e);
        }

        INSTANCE.start();         //26、調(diào)用 start 方法

        if (closeStandardStreams) {
            closeSysError();
        }
    } catch (NodeValidationException | RuntimeException e) {
        // disable console logging, so user does not see the exception twice (jvm will show it already)
        final Logger rootLogger = ESLoggerFactory.getRootLogger();
        final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class);
        if (foreground && maybeConsoleAppender != null) {
            Loggers.removeAppender(rootLogger, maybeConsoleAppender);
        }
        Logger logger = Loggers.getLogger(Bootstrap.class);
        if (INSTANCE.node != null) {
            logger = Loggers.getLogger(Bootstrap.class, Node.NODE_NAME_SETTING.get(INSTANCE.node.settings()));
        }
        // HACK, it sucks to do this, but we will run users out of disk space otherwise
        if (e instanceof CreationException) {
            // guice: log the shortened exc to the log file
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            PrintStream ps = null;
            try {
                ps = new PrintStream(os, false, "UTF-8");
            } catch (UnsupportedEncodingException uee) {
                assert false;
                e.addSuppressed(uee);
            }
            new StartupException(e).printStackTrace(ps);
            ps.flush();
            try {
                logger.error("Guice Exception: {}", os.toString("UTF-8"));
            } catch (UnsupportedEncodingException uee) {
                assert false;
                e.addSuppressed(uee);
            }
        } else if (e instanceof NodeValidationException) {
            logger.error("node validation exception
{}", e.getMessage());
        } else {
            // full exception
            logger.error("Exception", e);
        }
        // re-enable it if appropriate, so they can see any logging during the shutdown process
        if (foreground && maybeConsoleAppender != null) {
            Loggers.addAppender(rootLogger, maybeConsoleAppender);
        }
        throw e;
    }
}

該方法主要有:

1、創(chuàng)建 Bootstrap 實(shí)例

2、如果注冊(cè)了安全模塊則將相關(guān)配置加載進(jìn)來(lái)

3、創(chuàng)建 Elasticsearch 運(yùn)行的必須環(huán)境以及相關(guān)配置, 如將 config、scripts、plugins、modules、logs、lib、bin 等配置目錄加載到運(yùn)行環(huán)境中

4、log 配置環(huán)境,創(chuàng)建日志上下文

5、檢查是否存在 PID 文件,如果不存在,創(chuàng)建 PID 文件

6、檢查 Lucene 版本

7、調(diào)用 setup 方法(用當(dāng)前環(huán)境來(lái)創(chuàng)建一個(gè)節(jié)點(diǎn))

setup 方法
private void setup(boolean addShutdownHook, Environment environment) throws BootstrapException {
    Settings settings = environment.settings();//根據(jù)環(huán)境得到配置
    try {
        spawner.spawnNativeControllers(environment);
    } catch (IOException e) {
        throw new BootstrapException(e);
    }
    initializeNatives(
        environment.tmpFile(),
        BootstrapSettings.MEMORY_LOCK_SETTING.get(settings),
        BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(settings),
        BootstrapSettings.CTRLHANDLER_SETTING.get(settings));
    // initialize probes before the security manager is installed
    initializeProbes();
    if (addShutdownHook) {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    IOUtils.close(node, spawner);
                    LoggerContext context = (LoggerContext) LogManager.getContext(false);
                    Configurator.shutdown(context);
                } catch (IOException ex) {
                    throw new ElasticsearchException("failed to stop node", ex);
                }
            }
        });
    }
    try {
        // look for jar hell
        final Logger logger = ESLoggerFactory.getLogger(JarHell.class);
        JarHell.checkJarHell(logger::debug);
    } catch (IOException | URISyntaxException e) {
        throw new BootstrapException(e);
    }
    // Log ifconfig output before SecurityManager is installed
    IfConfig.logIfNecessary();
    // install SM after natives, shutdown hooks, etc.
    try {
        Security.configure(environment, BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(settings));
    } catch (IOException | NoSuchAlgorithmException e) {
        throw new BootstrapException(e);
    }
    node = new Node(environment) {              //16、新建節(jié)點(diǎn)
        @Override
        protected void validateNodeBeforeAcceptingRequests(
            final BootstrapContext context,
            final BoundTransportAddress boundTransportAddress, List checks) throws NodeValidationException {
            BootstrapChecks.check(context, boundTransportAddress, checks);
        }
    };
}

上面代碼最后就是 Node 節(jié)點(diǎn)的創(chuàng)建,這篇文章就不講 Node 的創(chuàng)建了,下篇文章會(huì)好好講一下 Node 節(jié)點(diǎn)的創(chuàng)建和正式啟動(dòng) ES 節(jié)點(diǎn)的。

總結(jié)

這篇文章主要先把大概啟動(dòng)流程串通,因?yàn)槠^多所以拆開(kāi)成兩篇,先不扣細(xì)節(jié)了,后面流程啟動(dòng)文章寫(xiě)完后我們?cè)賳我坏目奂?xì)節(jié)。

相關(guān)文章

1、渣渣菜雞為什么要看 ElasticSearch 源碼?

2、渣渣菜雞的 ElasticSearch 源碼解析 —— 環(huán)境搭建

3、渣渣菜雞的 ElasticSearch 源碼解析 —— 啟動(dòng)流程(上)

4、渣渣菜雞的 ElasticSearch 源碼解析 —— 啟動(dòng)流程(下)

5、Elasticsearch 系列文章(一):Elasticsearch 默認(rèn)分詞器和中分分詞器之間的比較及使用方法

6、Elasticsearch 系列文章(二):全文搜索引擎 Elasticsearch 集群搭建入門(mén)教程

7、Elasticsearch 系列文章(三):ElasticSearch 集群監(jiān)控

8、Elasticsearch 系列文章(四):ElasticSearch 單個(gè)節(jié)點(diǎn)監(jiān)控

9、Elasticsearch 系列文章(五):ELK 實(shí)時(shí)日志分析平臺(tái)環(huán)境搭建

10、教你如何在 IDEA 遠(yuǎn)程 Debug ElasticSearch

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/76906.html

相關(guān)文章

  • 渣的 ElasticSearch 源碼解析 —— 啟動(dòng)流程(下)

    摘要:關(guān)注我轉(zhuǎn)載請(qǐng)務(wù)必注明原創(chuàng)地址為前提上篇文章寫(xiě)完了流程啟動(dòng)的一部分,方法都入口,以及創(chuàng)建運(yùn)行的必須環(huán)境以及相關(guān)配置,接著就是創(chuàng)建該環(huán)境的節(jié)點(diǎn)了。的創(chuàng)建看下新建節(jié)點(diǎn)的代碼代碼比較多,這里是比較關(guān)鍵的地方,我就把注釋直接寫(xiě)在代碼上面了,實(shí)在不好 關(guān)注我 showImg(https://segmentfault.com/img/remote/1460000012730965?w=258&h=2...

    ztyzz 評(píng)論0 收藏0
  • 渣的 ElasticSearch 源碼解析 —— 環(huán)境搭建

    摘要:注意這個(gè)版本需要和下面的源碼版本一致下載源碼從上下載相應(yīng)版本的源代碼,這里建議用,這樣的話后面你可以隨意切換到的其他版本去。我們看下有哪些版本的找到了目前源碼版本最新的版本的穩(wěn)定版為切換到該版本于是就可以切換到該穩(wěn)定版本了。 關(guān)注我 showImg(https://segmentfault.com/img/remote/1460000012730965?w=258&h=258); 轉(zhuǎn)載...

    wudengzan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<