RocketMQ源码--4--NameServer启动过程

RocketMQ源码–4NameServer源码

文章目录

1 源码启动NameServer

​ 源码启动其实挺简单的,首先你去RocketMQ官网,将源码包下载下来,然后使用idea打开,直接启动,你会发现控制台提示你需要配置一个环境变量ROCKETMQ_HOME,所以这时候,我们就直接在idea中配置一个环境变量ROCKETMQ_HOME,并将它的值指定为当前项目的根路径,比如我的配置就是ROCKETMQ_HOME=D:\java学习\rocketmq\rocketmq-release-4.7.0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m9WczlSZ-1622875737784)(image\Snipaste_2021-06-05_13-59-41.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nj1njRLk-1622875737796)(image\Snipaste_2021-06-05_13-45-30.png)]

​ 这样配置好了之后,接下来就需要将配置文件复制过来了。

​ 直接在ROCKETMQ_HOME指定的路径下面新建一个文件夹conf,然后将二进制包中conf目录下的logback_namesrv.xml配置文件拷贝到你新建的文件夹conf目录下。

​ 最后直接启动就ok了。

2 NameServer启动过程

NameServer启动类的完全限定名为org.apache.rocketmq.namesrv.NamesrvStartup,我们从这个类的main()方法开始跟踪,看看启动过程中做了哪些事情?

public static void main(String[] args) {
    // 调用下面的main0()方法启动
    main0(args);
}

public static NamesrvController main0(String[] args) {

    try {
        // 创建NamesrvController,见2.1
        NamesrvController controller = createNamesrvController(args);
        // 启动NamesrvController,见2.2
        start(controller);
        String tip = "The Name Server boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
        log.info(tip);
        System.out.printf("%s%n", tip);
        return controller;
    } catch (Throwable e) {
        e.printStackTrace();
        System.exit(-1);
    }

    return null;
}

2.1 创建NamesrvController

public static NamesrvController createNamesrvController(String[] args) throws IOException, JoranException {
    // REMOTING_VERSION_KEY = "rocketmq.remoting.version" 保存当前RocketMQ的版本号
    System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));
    //PackageConflictDetect.detectFastjson();

    // 命令行参数mqnamesrv解析
    Options options = ServerUtil.buildCommandlineOptions(new Options());
    commandLine = ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options), new PosixParser());
    if (null == commandLine) {
        System.exit(-1);
        return null;
    }

    // 创建一个NameServer配置文件类对象
    final NamesrvConfig namesrvConfig = new NamesrvConfig();
    // 创建一个netty服务端配置文件类对象
    final NettyServerConfig nettyServerConfig = new NettyServerConfig();
    // 设置通信端口号为9876
    nettyServerConfig.setListenPort(9876);
    
    // 命令行参数c解析
    if (commandLine.hasOption('c')) {
        String file = commandLine.getOptionValue('c');
        if (file != null) {
            InputStream in = new BufferedInputStream(new FileInputStream(file));
            properties = new Properties();
            properties.load(in);
            MixAll.properties2Object(properties, namesrvConfig);
            MixAll.properties2Object(properties, nettyServerConfig);

            namesrvConfig.setConfigStorePath(file);

            System.out.printf("load config properties file OK, %s%n", file);
            in.close();
        }
    }

    
    // 命令行参数p解析
    if (commandLine.hasOption('p')) {
        InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME);
        MixAll.printObjectProperties(console, namesrvConfig);
        MixAll.printObjectProperties(console, nettyServerConfig);
        System.exit(0);
    }

    // 还是命令行参数解析,这个先不管,我们先看主流程
    MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);

    // 判断是否配置了ROCKETMQ_HOME这个环境变量,没有配置,在此处就会报错
    if (null == namesrvConfig.getRocketmqHome()) {
        System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation%n", MixAll.ROCKETMQ_HOME_ENV);
        System.exit(-2);
    }

    // 日志配置,可以发现日志的配置文件是环境变量ROCKETMQ_HOME下面conf目录
    // 下面的logback_namesrv.xml文件,这是固定的
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    JoranConfigurator configurator = new JoranConfigurator();
    configurator.setContext(lc);
    lc.reset();
    configurator.doConfigure(namesrvConfig.getRocketmqHome() + "/conf/logback_namesrv.xml");

    log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);

    // 打印日志相关配置信息
    MixAll.printObjectProperties(log, namesrvConfig);
    MixAll.printObjectProperties(log, nettyServerConfig);

    // 直接new一个NamesrvController对象
    final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);

    // remember all configs to prevent discard
    // 记住所有配置,防止丢失
    controller.getConfiguration().registerConfig(properties);

    return controller;
}

总结一下这个方法的流程:

  1. 解析命令行参数mqnamesrv
  2. 初始化两个配置对象(NamesrvConfigNettyServerConfig
  3. 解析命令行参数c
  4. 解析命令行参数p
  5. 解析conf/logback_namesrv.xml文件,应用指定配置生成log对象
  6. 根据两个配置对象生成一个NamesrvController对象
  7. 记住配置,防止丢失

梳理一下这个流程,还是挺简单的,我们重点看一下26

2.1.1 初始化配置对象NamesrvConfig

NamesrvConfig只有一个默认的构造方法,但是类中的几个字段都指定了默认值

public class NamesrvConfig {
    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);

    // ROCKETMQ_HOME_PROPERTY = "rocketmq.home.dir"
    // ROCKETMQ_HOME_ENV = "ROCKETMQ_HOME"
    // System.getProperty(key,def)这个方法会先去系统中找key对应的值,如果为null,则
    // 返回后面def值,其实def就相当于一个默认值
    private String rocketmqHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY, System.getenv(MixAll.ROCKETMQ_HOME_ENV));
    // separator = "\" 
    // 默认为C:\Users\Administrator\namesrv\kvConfig.json
    private String kvConfigPath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "kvConfig.json";
    // 默认为C:\Users\Administrator\namesrv\namesrv.properties
    private String configStorePath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "namesrv.properties";
    private String productEnvName = "center";
    private boolean clusterTest = false;
    private boolean orderMessageEnable = false;
}

在创建对象的时候,所有的字段全部已经给定了初始值

2.1.2 初始化配置对象NettyServerConfig

NettyServerConfig同样只有一个默认的构造方法,且类中的几个字段都指定了默认值

public class NettyServerConfig implements Cloneable {
    private int listenPort = 8888;
    private int serverWorkerThreads = 8;
    private int serverCallbackExecutorThreads = 0;
    private int serverSelectorThreads = 3;
    private int serverOnewaySemaphoreValue = 256;
    private int serverAsyncSemaphoreValue = 64;
    private int serverChannelMaxIdleTimeSeconds = 120;

    private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize;
    private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize;
    private boolean serverPooledByteBufAllocatorEnable = true;

    /**
     * make make install
     *
     *
     * ../glibc-2.10.1/configure \ --prefix=/usr \ --with-headers=/usr/include \
     * --host=x86_64-linux-gnu \ --build=x86_64-pc-linux-gnu \ --without-gd
     */
    private boolean useEpollNativeSelector = false;
}

在创建对象的时候,所有的字段全部已经给定了初始值

上一篇:深入浅出!传智播客Java视频教程


下一篇:创建jenkins容器,并搭建python3+pytest+allure测试环境