一、前言

众所周知,Tomcat是作为一款优秀的web服务容器被广泛应用。Tomcat是基于J2EE规范实现了经典的双亲委派模型的类加载体系。

二、相关概念

1JAVA虚拟机主要的类加载器:

aBootstrap Loader:加载lib目录下或者System.getProperty("sun.boot.class.path")、或者-XBootclasspath所指定的路径或jar

bExtended Loader:加载lib\ext目录下或者System.getProperty("java.ext.dirs")所指定的路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java-Djava.ext.dirs=d:\projects\testproj\classes HelloWorld

cAppClass 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 ClassLoaderApp ClassLoader也继承这个类。但是Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoaderApp ClassLoader类加载器。

三、tomcat类加载加载机制

1、前言中已经提到tomcat类加载机制是基于J2EE的双亲委派模式,双亲委派模式此处就不再赘述。tomcat在双亲委派模式基础上定制了自己的类加载器,其类加载体系图如下:


从上图片看出tomcat的类加载体系中包含以下几个类加载器:

aClassLoaderJava提供的类加载器抽象类,用户自定义的类加载器需要继承实现;

bcommonLoaderTomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;

ccatalinaLoaderTomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;

dsharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;

eWebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;

四、tomcat启动源码分析(tomcat8为例)

1tomcat启动从执行 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的初始化及设置当前线程的类加载器。

2main访问中调用的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;
}

上述代码执行的逻辑说明如下:

ainitClassLoaders()方法中初始化了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类中相应的方法执行操作。

4org.apache.catalina.startup.Catalina类中封装了所有的tomcat相关逻辑方法。主要的方法有:

aload()方法,主要是加载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的,这是apachecommon项目。

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) {

cstop()方法,主要用于停止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 {

dstopServer()方法,用于停止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;




Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐