分享tomcat源码系列一

原文连接:http://simpleframework.net/blog/v/16313.html

最近在看Tomcat的源码,下面用博客记下看源码的一些心得。

Tomcat是从org.apache.catalina.startup.Bootstrap#main()开始启动. 大致分为三个步骤,即init、load和start。代码如下:

Java代码

public static void main(String args[]) {     
        try {     
            // Attempt to load JMX class     
            new ObjectName("test:foo=bar");     
        } catch (Throwable t) {     
            System.out.println(JMX_ERROR_MESSAGE);     
            try {     
                // Give users some time to read the message before exiting     
                Thread.sleep(5000);     
            } catch (Exception ex) {     
            }     
            return;     
        }     
        if (daemon == null) {     
            daemon = new Bootstrap();     
            try {     
                daemon.init();   ★1     
            } catch (Throwable t) {     
                t.printStackTrace();     
                return;     
            }     
        }     
        try {     
            String command = "start";     
            if (args.length > 0) {     
                command = args[args.length - 1];     
            }     
            if (command.equals("startd")) {     
                args[0] = "start";     
                daemon.load(args);     
                daemon.start();     
            } else if (command.equals("stopd")) {     
                args[0] = "stop";     
                daemon.stop();     
            } else if (command.equals("start")) {     
                daemon.setAwait(true);     
                daemon.load(args);   ★2     
   
             // 反射调用Catalina的start方法     
                daemon.start();        ★3     
            } else if (command.equals("stop")) {     
                daemon.stopServer(args);     
            }     
        } catch (Throwable t) {     
            t.printStackTrace();     
        }     
    }     
从以上可以很清楚的看出tomcat是通过参数的不同进行相应的命令调用。

★1 启动、初始化(加载类)

启动之前要进行相应的init()初始化,进行相应的环境设置以及包的加,以下是init()方法。(org.apache.catalina.startup.Bootstrap.init())

Java代码

public void init()     
        throws Exception     
    {     
        setCatalinaHome();//设置Catalina安装目录     
        setCatalinaBase();//设置Catalina工作目录     
        initClassLoaders();//加载jar包     
   
       // 将classload设置进线程,以便我们使用时进行调用           
        Thread.currentThread().     
                      setContextClassLoader(catalinaLoader);     
        SecurityClassLoad.securityClassLoad(catalinaLoader);     
   
        // 加载启动类和调用它的process方法     
        if (log.isDebugEnabled())     
            log.debug("Loading startup class");     
        Class startupClass =     
            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[1];     
        paramTypes[0] = Class.forName("java.lang.ClassLoader");     
        Object paramValues[] = new Object[1];     
        paramValues[0] = sharedLoader;     
        Method method =     
        startupInstance.getClass().getMethod(methodName,     
                                                          paramTypes);     
        method.invoke(startupInstance, paramValues);     
        catalinaDaemon = startupInstance;     
    } 
在加载jar的时候,需要初始化classloader,代码如下:(org.apache.catalina.startup.Bootstrap)

Java代码

private void initClassLoaders() {     
        try {     
            commonLoader = createClassLoader("common", null);     
            catalinaLoader= createClassLoader("server", commonLoader);     
            sharedLoader = createClassLoader("shared", commonLoader);     
        } catch (Throwable t) {     
            log.error("Class loader creation threw exception", t);     
            System.exit(1);     
        }     
    }  
tomcat中的加载方式是:

|-------commonLoader (common)-> System Loader

|-------sharedLoader (shared)-> commonLoader -> System Loader

|-------catalinaLoader(server) -> commonLoader -> System Loader

Common是公共类加载器,负责加载tomcat内部和web应用程序可以看到的类(%CATALINA_HOME%/bin/common下的jar文件),Catalina负责加载的是tomcat内部使用的类(%CATALINA_HOME%/server下的jar文件),这些类对web应用程序不可见。Shared负责加载的是web应用程序之间共享的类(%CATALINA_BASE%/shared下的jar文件),这些类对于tomcat内部是不可见的。如果%CATALINA_HOME%/conf/catalina.Properties中没有指定Common的搜索路径,则用当前的类的类加载器即系统类加载器作为Common。

★2 装载相应的资源

下面主要讲解tomcat的load()方法。下图是Catalina.load方法的时序图。


(1) 从上面的时序图可以看出首先调用Catalina类的load()方法,具体代码如下:

(org.apache.catalina.startup.Catalina)。

Java代码

public void load() {     
        initDirs();     
   
        // Before digester - it may be needed     
        initNaming();     
   
        // Create and execute our Digester     
        Digester digester = createStartDigester();     
           
        try {     
            inputSource.setByteStream(inputStream);     
            digester.push(this);     
            digester.parse(inputSource); //对server.xml进行解析     
            inputStream.close();     
        }     
       ......     
        // Start the new server     
        if (server instanceof Lifecycle) {     
            try {     
                server.initialize();  //server初始化工作     
            } catch (LifecycleException e) {     
                log.error("Catalina.start", e);     
            }     
        }     
        long t2 = System.currentTimeMillis();     
        log.info("Initialization processed in " + (t2 - t1) + " ms");     
   
    }    
(2) 在上面的load()方法中需要进行server的初始化工作,下图为Catalina.initialize的时序图,从图中可以看出server初始化所完成的工作。


至此,load方法结束,初期化的工作结束,下面开始进入start方法。

★3 容器启动

容器启动时,会调用Catalina.start(),下图为它的时序图。从图中可以看出StandardService的start方法被调用后会分别对Container和Connector进行start方法的调用。


1. Bootstrap调用Catalina的start方法

Catalina.start()方法(org.apache.catalina.startup.Catalina.start())

Java代码

public void start() {     
    // 启动server     
    if (server instanceof Lifecycle) {     
        try {     
            ((Lifecycle) server).start();     
                    ......     
   }    
2. Catalina调用StandardServer的start方法

StandardServer.start() (org.apache.catalina.core.StandardServer.start() )

Java代码

public void start() throws LifecycleException {           
        synchronized (services) {     
            for (int i = 0; i < services.length; i++) {     
                if (services[i] instanceof Lifecycle)     
                    ((Lifecycle) services[i]).start();     
            }      
}  
3. StandardServer调用StandardService的start方法

Java代码

org.apache.catalina.core.StandardService.start() )     
        public void start() throws LifecycleException {     
                  if (container != null) {     
            synchronized (container) {     
                if (container instanceof Lifecycle) {     
              //  standardEngine的启动     
                    ((Lifecycle) container).start();     
                }     
            }     
       //两个connector的启动,8080和8009       
       synchronized (connectors) {       
           for (int i = 0; i < connectors.length; i++) {       
               if (connectors[i] instanceof Lifecycle)       
                   ((Lifecycle) connectors[i]).start();       
                  }       
       }       

以上StandardService.start()方法主要实现了两个功能,standardEngine的启动和connector的启动,下面分别来介绍。

猜你喜欢

转载自fjg0427.iteye.com/blog/1662018