Tomcat实现分析(一)--类加载及容器组件

启动脚本

启动命令中的参数如下:

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

  1. 使用JDK的java.util.logging的局限

    一旦使用了JUL,那就意味着其是全局(整个JVM级别)共享,但是Tomcat作为一个Servlet容器(可以部署多个应用,每个应用的日志应该隔离),这种局限是不能接受的;同时,考虑到Tomcat内部本身日志可以动态替换实现,Tomcat开发了Java Util Logging Implementation(以下简称JULI);

  2. JULI的特性

    1. 覆盖JUL的LoggerManager(通过-Djava.util.logging.manager指定),支持ClassLoader粒度的日志输出;
    2. JULI默认采用DirectJDKLog来实现,本质就是JUL;
    3. 可以通过替换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,这个类职责比较简单:

  1. 完成Tomcat中classLoader的初始化;
  2. 通过Catalina类,引导Tomcat启动;

Tomcat的ClassLoader结构如下:

  1. AppClassLoader,即SystemClassLoader,通过-classpath指定;这里只包含Tomcat的启动类、依赖的ClassLoader实现类以及对JUL的增强(JULI);
  2. CommonLoader,通过$CATALINA_BASE/conf/catalina.properties中的common.loader指定,包括:$CATALINA_BASE/lib以及$CATALINA_HOME/lib下的classes、resources和jar包;

    CommonLoader为整个Tomcat和所有webapp所共享

  3. CatalinaLoader和SharedLoader,在官方的实现里,其仓库是空的,只是共享CommonLoader的仓库;
  4. 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内部组件及其关系:

其中:

  1. Tomcat的启动是各组件从外到内调用,从内到外完成;
  2. Server组件监听本地的8005端口,实现异步关闭Tomcat容器;
  3. 除了Catalina作为引导容器,其余窗口均实现LifeCycle,都可以包含多个LifeCycleListener;
  4. Engine及其子容器,均实现了Container,可以包含Pipeline, Logger, Loader, Realm, Manager等组件;
  5. 所有的Servlet均被包装成Wrapper组件;
posted @ 2014-01-22 17:02  diecui1202  阅读(258)  评论(0编辑  收藏  举报