启动脚本
启动命令中的参数如下:
org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/opt/apache/apache-tomcat-7.0.47/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=7999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.endorsed.dirs=/opt/apache/apache-tomcat-7.0.47/endorsed -Dcatalina.base=/opt/apache/apache-tomcat-7.0.47 -Dcatalina.home=/opt/apache/apache-tomcat-7.0.47 -Djava.io.tmpdir=/opt/apache/apache-tomcat-7.0.47/temp
Tomcat Logging
启动参数里,其classpath中有/opt/apache/apache-tomcat-7.0.47/bin/tomcat-juli.jar
,另外通过-D
传递了两个属性:
-Djava.util.logging.config.file=/opt/apache/apache-tomcat-7.0.47/conf/logging.properties
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
Tomcat默认采用的是JDK 1.4中引入的Java Util Logging(以下简称 JUL)日志组件,通过指定系统参数java.util.logging.config.file
来设置日志输出级别、Handler等;
更多关于JUL的信息,可以参考Java™ Logging Overview;
-
使用JDK的java.util.logging的局限
一旦使用了JUL,那就意味着其是全局(整个JVM级别)共享,但是Tomcat作为一个Servlet容器(可以部署多个应用,每个应用的日志应该隔离),这种局限是不能接受的;同时,考虑到Tomcat内部本身日志可以动态替换实现,Tomcat开发了Java Util Logging Implementation(以下简称JULI);
-
JULI的特性
- 覆盖JUL的LoggerManager(通过-Djava.util.logging.manager指定),支持ClassLoader粒度的日志输出;
- JULI默认采用DirectJDKLog来实现,本质就是JUL;
- 可以通过替换Tomcat的$CATALINA_BASE/bin下的tomcat-juli.jar,同时在$CATALINA_BASE/lib下新增log4j.jar、tomcat-juli-adapters.jar、log4j.properties,即可将其实现替换为log4j(具体步骤可参考Logging in Tomcat);
Tomcat类加载器
启动类为:org.apache.catalina.startup.Bootstrap
,这个类职责比较简单:
- 完成Tomcat中classLoader的初始化;
- 通过Catalina类,引导Tomcat启动;
Tomcat的ClassLoader结构如下:
- AppClassLoader,即SystemClassLoader,通过-classpath指定;这里只包含Tomcat的启动类、依赖的ClassLoader实现类以及对JUL的增强(JULI);
-
CommonLoader,通过$CATALINA_BASE/conf/catalina.properties中的common.loader指定,包括:$CATALINA_BASE/lib以及$CATALINA_HOME/lib下的classes、resources和jar包;
CommonLoader为整个Tomcat和所有webapp所共享
; - CatalinaLoader和SharedLoader,在官方的实现里,其仓库是空的,只是共享CommonLoader的仓库;
-
WebAppClassLoader,每个webapp创建一个,webapp之间是隔离的,包括WEB-INF/classes以及WEB-INF/lib下的所有class和jar包;
WebAppClassLoader加载类的方式与普通的双亲委派不一样,它是先从本地仓库加载,加载不到,再委派给parent ClassLoader(特殊类除外,比如JRE的类总是委派给parent,Servlet API相关的类则会被忽略,交由CommonLoader加载);
一个WebApp的类加载顺序如下:
- Bootstrap classes of your JVM
- System class loader classes(AppClassLoader)
- /WEB-INF/classes of your web application
- /WEB-INF/lib/*.jar of your web application
- Common class loader classes(CommonLoader)
启动Tomcat
Tomcat主配置文件位于conf/server.xml,Bootstrap通过引导Catalina来解析server.xml,从而启动tomcat;
解析server.xml是通过Degister来完成的;
下面这张图描述了Tomcat内部组件及其关系:
其中:
- Tomcat的启动是各组件从外到内调用,从内到外完成;
- Server组件监听本地的8005端口,实现异步关闭Tomcat容器;
- 除了Catalina作为引导容器,其余窗口均实现LifeCycle,都可以包含多个LifeCycleListener;
- Engine及其子容器,均实现了Container,可以包含Pipeline, Logger, Loader, Realm, Manager等组件;
- 所有的Servlet均被包装成Wrapper组件;