`
toking79
  • 浏览: 22585 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Tomcat源码系列1--Tomcat启动流程1

阅读更多

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

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

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

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)

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

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

    public void start() { 
        // 启动server 
        if (server instanceof Lifecycle) { 
            try { 
                ((Lifecycle) server).start(); 
                        ...... 
       } 

 
2. Catalina调用StandardServer的start方法
StandardServer.start() (org.apache.catalina.core.StandardServer.start() ) 

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方法

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的启动,下面分别来介绍。

 

  • 大小: 16.4 KB
  • 大小: 10.9 KB
  • 大小: 15.8 KB
1
4
分享到:
评论
1 楼 xuhang1128 2011-03-20  
学习了,看完您的文章自己再去看看能够更清晰点

相关推荐

Global site tag (gtag.js) - Google Analytics