Tomcat启动流程解析
来源:互联网 发布:淘宝我的小蜜是客服么 编辑:程序博客网 时间:2024/05/21 11:20
一、前言
众所周知,Tomcat是作为一款优秀的web服务容器被广泛应用。Tomcat是基于J2EE规范实现了经典的双亲委派模型的类加载体系。
二、相关概念
1、JAVA虚拟机主要的类加载器:
a、Bootstrap Loader:加载lib目录下或者System.getProperty("sun.boot.class.path")、或者-XBootclasspath所指定的路径或jar。
b、Extended Loader:加载lib\ext目录下或者System.getProperty("java.ext.dirs")所指定的路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java-Djava.ext.dirs=d:\projects\testproj\classes HelloWorld。
c、AppClass Loader:加载System.getProperty("java.class.path")所指定的路径或jar。在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classes HelloWorld。
2、双亲委派模式类加载体系
双亲委派模式类加载体系概念:每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。
双亲委派模式类加载体系图示:
从上图中可以看出,JVM虚拟机的类加载器执行的顺序为:
BootStrap ClassLoader > Extension ClassLoader > App ClassLoader,除了上述的类加载器之外,我们也可以定义自己的类加载器,但是这些自定义的类加载器都必须继承java.lang.ClassLoader类,同样Extension ClassLoader与App ClassLoader也继承这个类。但是Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。
三、tomcat类加载加载机制
1、前言中已经提到tomcat类加载机制是基于J2EE的双亲委派模式,双亲委派模式此处就不再赘述。tomcat在双亲委派模式基础上定制了自己的类加载器,其类加载体系图如下:
从上图片看出tomcat的类加载体系中包含以下几个类加载器:
a、ClassLoader:Java提供的类加载器抽象类,用户自定义的类加载器需要继承实现;
b、commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
c、catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
d、sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
e、WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;
四、tomcat启动源码分析(以tomcat8为例)
1、tomcat启动从执行 org.apache.catalina.startup.Bootstrap.main()方法开始。main方法主要实现的逻辑如下源码:
public static void main(String[] args) { if(daemon == null) { Bootstrap t = new Bootstrap(); try { t.init(); } catch (Throwable var3) { handleThrowable(var3); var3.printStackTrace(); return; } daemon = t; } else { Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } try { String t2 = "start"; if(args.length > 0) { t2 = args[args.length - 1]; } ……}
上叙代码主要实现的BootStrap的初始化及设置当前线程的类加载器。
2、main访问中调用的init()方法源码如下:
public void init() throws Exception { this.initClassLoaders(); Thread.currentThread().setContextClassLoader(this.catalinaLoader); SecurityClassLoad.securityClassLoad(this.catalinaLoader); if(log.isDebugEnabled()) { log.debug("Loading startup class"); } Class startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); if(log.isDebugEnabled()) { log.debug("Setting startup class properties"); } String methodName = "setParentClassLoader"; Class[] paramTypes = new Class[]{Class.forName("java.lang.ClassLoader")}; Object[] paramValues = new Object[]{this.sharedLoader}; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); this.catalinaDaemon = startupInstance;}
上述代码执行的逻辑说明如下:
a、initClassLoaders()方法中初始化了commonLoader,catalinaLoader,sharedLoader这几个类加载器,具体初始化过程可以参看源码
b、设置当前线程的类加载器setContextClassLoader,设置安全的类加载器ecurityClassLoad.securityClassLoad(this.catalinaLoader);
c、通过java反射机制初始化org.apache.catalina.startup.Catalina并执行setParentClassLoader方法
3、同时main方法中还有部分源码如下:
String t2 = "start";if(args.length > 0) { t2 = args[args.length - 1];}if(t2.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start();} else if(t2.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop();} else if(t2.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start();} else if(t2.equals("stop")) { daemon.stopServer(args);} else if(t2.equals("configtest")) { daemon.load(args); if(null == daemon.getServer()) { System.exit(1); } System.exit(0);
上述代码中的dameon.stopServer(),dameon.start(),dameon.load()都需要通过反射机制调用到org.apache.catalina.startup.Catalina类中相应的方法执行操作。
4、org.apache.catalina.startup.Catalina类中封装了所有的tomcat相关逻辑方法。主要的方法有:
a、load()方法,主要是加载server.xml配置及初始化相关资源部分源码如下:
public void load() { long t1 = System.nanoTime(); this.initDirs(); this.initNaming(); Digester digester = this.createStartDigester(); InputSource inputSource = null; Object inputStream = null; File file = null; label257: { try { try { file = this.configFile();
其中server.xml是用Digester这个工具来parse的,这是apache的common项目。
b、start()方法,主要是用于启动tomcat容器的。部分源码如下:public void start() { if(this.getServer() == null) { this.load(); } if(this.getServer() == null) { log.fatal("Cannot start server. Server instance is not configured."); } else { long t1 = System.nanoTime(); try { this.getServer().start(); } catch (LifecycleException var7) {
c、stop()方法,主要用于停止tomcat服务,部分源码如下:
public void stop() { try { if(this.useShutdownHook) { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); LogManager e = LogManager.getLogManager(); if(e instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager)e).setUseShutdownHook(true); } } } catch (Throwable var3) { ExceptionUtils.handleThrowable(var3); } try {
d、stopServer()方法,用于停止tomcat容器,部分源码如下:
public void stopServer(String[] arguments) { if(arguments != null) { this.arguments(arguments); } Server s = this.getServer(); if(s == null) { Digester e = this.createStopDigester(); File file = this.configFile(); Throwable var6; try { FileInputStream x2 = new FileInputStream(file); var6 = null;
- Tomcat启动流程解析
- tomcat-tomcat启动流程
- tomcat启动流程日志
- tomcat流程原理解析
- 计算机启动流程解析
- eCos启动流程解析
- Arm启动流程解析
- 解析STM32启动流程
- SpringBoot启动流程解析
- SpringBoot启动流程解析
- tomcat启动解析
- tomcat服务启动解析
- Tomcat源码解析(五):Connector连接器的初始化和启动流程
- android app启动流程解析
- Activity 启动流程源码解析
- Service 启动流程源码解析
- PackageManagerService启动流程源码解析
- springmvc启动流程源码解析
- JSTL的使用和语法规则
- Linux-QT4.7 实现串口通信
- 解决在spring配置文件中包扫描无效问题
- Centos 不联网安装配置Opencv
- 继承 重写 自动转型/ 多态
- Tomcat启动流程解析
- 第六篇:微服务部署策略的选择
- 转载自网上的即时通讯 稍微修改了一下bug
- declare handler 声明异常处理的语法
- hdu 2066 一个人的旅行【vector优化】
- 面向过程理解以及引申
- 广度优先搜索
- 初学安卓所犯下的蠢事
- C++实训二