RocketMQ
源码–4
–NameServer
源码
文章目录
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;
}
总结一下这个方法的流程:
- 解析命令行参数
mqnamesrv
- 初始化两个配置对象(
NamesrvConfig
、NettyServerConfig
)- 解析命令行参数
c
- 解析命令行参数
p
- 解析
conf/logback_namesrv.xml
文件,应用指定配置生成log
对象- 根据两个配置对象生成一个
NamesrvController
对象- 记住配置,防止丢失
梳理一下这个流程,还是挺简单的,我们重点看一下
2
和6
。
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;
}
在创建对象的时候,所有的字段全部已经给定了初始值