先大致看一下外部启动一个Jetty服务器的过程,然后再展开分析
1.java start.jar进行启动,解析命令行参数并读取start.ini中配置的所有参数。
2.解析start.config确定jetty模块的类路径并确定首先执行的MainClass。
3.可以选择是否另起一个进程来,如果不另起进程,则通过反射方式来调用MainClass,start.ini中配置的JVM参数不会生效。
4.MainClass默认是XmlConfiguration,解析etc/jetty.xml,etc/jetty-deploy.xml等,创建实例并组装Server(是根据在start.ini中定义的顺序创建,顺序很重要,这里的IOC是jetty自己实现的)然后调用start()启动Server()。
1.start.jar启动分析
我们可以通过java -jar start.jar 命令来启动jetty,所以首先从start.jar开始分析。这个jar中包含了解析命令行参数的Main类,Main主要负责解析命令行中传入的参数以及start.ini文件中配置的参数。start.ini 中定义了 JVM 需要的参数以及 etc 目录中用到的xml配置文件和启动jetty启动时需要加载的模块,如下图:
然后由Config类解析出start.ini中OPTIONS选项指定的模块包位置并加入到classpath中,这些模块包都定义在在start.config文件中,通过在 start.ini 中定义 OPTIONS 以及在 start.config 中定义模块路径就可以确定把哪些 jar 加入到环境变量中。
以上准备工作做完之后就可以真正开始服务器处理了,这时候可以在本进程中直接通过反射方式启动,但缺点是start.ini中配置的JVM参数就如同虚设了,
因为Java进程已经起来了,不能再按照新的堆参数进行设置了;第二种方式就是重新启动一个进程,这样就可以重新设置堆参数了,start.ini 中得到了启动参数start.config 中有了MainClass和Classpath需要的jar包,则可以直接用java xxx方式启动了,要使用这种方式启动只需要在 start.ini 中配置 –exec 参数即可。
这里的MainClass默认是XmlConfiguration类,它默认做几件事情:1.对start.ini中定义的配置文件进行解析,例如/etc/jetty.xml等。2.通过自己的IOC将这些组件组装在一起,最后调用start()方法启动这些组件。
下面是start.jar中的Main类的main()方法:
public static void main(String[] args)
{
boolean test=false;
try
{
Main main = new Main();
//解析启动时在命令行传入的参数和start.ini中配置的参数
StartArgs startArgs = main.processCommandLine(args);
test=startArgs.isTestingModeEnabled()
//通过拼接好的参数启动XmlConfiguration类,有通过反射和另起一个jvm进程两种方式
main.start(startArgs);
}
catch (UsageException e)
{
StartLog.error(e.getMessage());
usageExit(e.getCause(),e.getExitCode(),test);
}
catch (Throwable e)
{
usageExit(e,UsageException.ERR_UNKNOWN,test);
}
}
上面讲到的如果在start.ini中配置了–exec参数就会另起一个进程是在main.start()方法实现,具体的代码如下:
// execute Jetty in another JVM
if (args.isExec())
{
CommandLineBuilder cmd = args.getMainArgs(true);
cmd.debug();
ProcessBuilder pbuilder = new ProcessBuilder(cmd.getArgs());
StartLog.endStartLog();
final Process process = pbuilder.start();
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run()
{
StartLog.debug("Destroying " + process);
process.destroy();
}
});
copyInThread(process.getErrorStream(),System.err);
copyInThread(process.getInputStream(),System.out);
copyInThread(System.in,process.getOutputStream());
process.waitFor();
System.exit(0); // exit JVM when child process ends.
return;
}
注意上面的注释,如果XMLConfiguration启动的进程结束了,那么start.jar对应的进程也会结束掉。
2.XmlConfiguration分析
上面说到默认的MainClass是XmlConfiguration,这个类的main()函数中负责解析xml配置文件利用自己的IOC组装Server。这里主要是用到xml文件来组装Server的过程,默认使用的是etc/jetty.xml,也可以在start.ini中指定其它文件,主要的流程是从xml文件中创建Server类,以及填充Server所需要的线程池 、connector、handler等组件. xml的部分配置如下,可以看到配置了connector handler和threadPool。
在XmlConfiguration解析完配置之后,就开始启动服务,jetty的启动是从Server的启动开始的。从XmlConfiguration中的main函数中可以看到,对那些继承了LifCycle的组件,会调用start()方法进行启动,而Server也是一个handler,所以会在下面的方法中进行启动。
// For all objects created by XmlConfigurations, start them if they are lifecycles.
for (Object obj : objects) {
if (obj instanceof LifeCycle) {
LifeCycle lc = (LifeCycle) obj;
if (!lc.isRunning()) {
lc.start();
}
}
}
XMLConfiguration解析完配置之后就开始真正启动服务了,Jetty的启动是从Server开始的。Server启动的时序图如下:
可以看到先配置好用户在xml文件中配置的核心组件,将它们作为bean加入到内部的bean数组中,ThreadPool也是作为自定义组件加入的。然后调用Server的start()方法进行启动,先启动handler处理器,再启动用户自定义组件,这里的用户自定义组件需要实现LifeCycle,最后再启动Connector接受用户请求。关闭的流程是相反的,先关闭Connector,再关闭用户自定义组件,最后再关闭handler处理器。
至此Jetty也就算是正式启动起来了,至于里面的Connector是如何接受用户请求、一系列Handler是如何处理请求、ThreadPool如何为前面两张提供线程,都会在后面的源码阅读中进行解析。
本文详细分析了Jetty服务器的启动过程,包括start.jar启动分析和XmlConfiguration的作用。start.jar解析命令行参数和start.ini配置,然后通过XmlConfiguration创建并启动Server。XmlConfiguration根据xml文件组装Server,包括线程池、connector和handler等组件。Jetty启动时,先启动handler,再启动用户自定义组件(实现LifeCycle接口),最后启动Connector接收用户请求。
1783

被折叠的 条评论
为什么被折叠?



