zoukankan      html  css  js  c++  java
  • tomcat7源代码Bootstrap

            tomcat的启动从bootstrap的main方法開始,在main方法中主要是做了三件事,调用init方法初始化自己。调用catalinaDaemon对象

    的setAwait方法设置它的await属性为true,最后调用自己的start方法。

            首先看看init方法:

      public void init()
            throws Exception
        {
    
            // Set Catalina path
            setCatalinaHome();
            setCatalinaBase();
    
            //初始化三个类载入器
            initClassLoaders();
    
             //线程构造后将从它的父线程中继承对应的上下文类载入器. 假设在整个应用中你不做不论什么特殊设置, 
            //全部的线程将都以系统类载入器(system classloader)作为自己的线程上下文类载入器.
            //这里从Bootstrap构造的线程都会继承改线程的上下文类载入器
            Thread.currentThread().setContextClassLoader(catalinaLoader);
    
            //载入conf下的catalina.properties配置文件下的common.loader和server.loader所指定的类。由于server.loader为空时
            //catalinaLoader和commonLoader是指向的同一对象,不为空时commonLoader是catalinaLoader的父类。
            SecurityClassLoad.securityClassLoad(catalinaLoader);
    
            // Load our startup class and call its process() method
            if (log.isDebugEnabled())
                log.debug("Loading startup class");
            Class<?

    > startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader 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; }

           这里的主要内容就是调用了initClassLoaders();初始化了commonLoader,catalinaLoader。sharedLoader三个类载入器。它们是bootstrap的

    成员变量。并通过SecurityClassLoad.securityClassLoad(catalinaLoader)这步代码来载入conf/catalina.properties文件下common.loader,

    server.loader,shared.loade三个属性指定的jar包和class。securityClassLoad会通过一系列环境变量替换等处理来找到相关的类并载入它们。

    最后一段代码初始化Catalina对象,再设置它的父类载入器为sharedLoader。

    这里的一些疑问稍后再说。

            先看看initClassLoaders()方法:

    initClassLoaders源代码:
       private void initClassLoaders() {
            try {
                commonLoader = createClassLoader("common", null);//1,创建commonLoader类载入器
                if( commonLoader == null ) {
                    // no config file, default to this loader - we might be in a 'single' env.
                    commonLoader=this.getClass().getClassLoader();
                }
                catalinaLoader = createClassLoader("server", commonLoader);//2,
                sharedLoader = createClassLoader("shared", commonLoader);//3,
            } catch (Throwable t) {
                handleThrowable(t);
                log.error("Class loader creation threw exception", t);
                System.exit(1);
            }
        }
          第一步是通过commonkeyword初始化了一个commonLoader对象。

          进到createClassLoader方法中:

     private ClassLoader createClassLoader(String name, ClassLoader parent)
            throws Exception {
            String value = CatalinaProperties.getProperty(name + ".loader");
            if ((value == null) || (value.equals("")))
                return parent;
            value = replace(value);
            ........
            ClassLoader classLoader = ClassLoaderFactory.createClassLoader
                (repositories, parent);
            ........
            return classLoader;
        }

          这里应该非常清楚,CatalinaProperties.getProperty(name + ".loader");就是获取配置文件中的属性的方法。

    value = replace(value)替换环境变量

    等一系列的转换获取了一些类路径的url最后将这些url传给ClassLoaderFactory.createClassLoader方法。

    CommonclassLoader和其它两个类载入器都

    是通过该方法获取的,它们是一个StandardClassLoader实例。

    StandardClassLoader仅仅是简单的从URLClassLoader继承,并实现了

    StandardClassLoaderMBean接口来实现JMX监控。

    所以能够觉得这三个类载入器就是URLClassLoader对象。

    createClassLoader(repositories, parent),事实上就是调用了URLClassLoader的构造方法,传入类路径的URL集合和父载入器。

    假设打开

    conf/catalina.properties配置文件。server.loader,shared.loade默觉得空。从createClassLoader方法中if推断就能够知道

    commonLoader == catalinaLoader == sharedLoader。

        这里先说一点设置这三个类载入器的用意,以后再用源代码证明。commonLoader被用来设置为catalinaLoader和sharedLoader的父载入器。

    catalinaLoader用来载入tomcat自身程序所须要的类。sharedLoader用来载入一些webapp文件夹下的程序共享的class。并被WebappClassLoader

    (用户web程序的类载入器)设置为父类(从这里就能够知道web程序的类是怎么实现相互隔离,但又能够共享某些jar包的。由于类载入器在载入

    类时会先让父载入器去载入,父载入器找不到的话就自己来载入,在这里sharedLoader和WebappClassLoader都有不同的载入路径,全部的

    WebappClassLoader都继承自sharedLoader,所以他们共享了sharedLoader的载入路径)。




        再来看看SecurityClassLoad.securityClassLoad(catalinaLoader):

    public static void securityClassLoad(ClassLoader loader)
            throws Exception {
    
            if( System.getSecurityManager() == null ){
                return;
            }
    
            loadCorePackage(loader);
            loadCoyotePackage(loader);
            loadLoaderPackage(loader);
            loadRealmPackage(loader);
            loadServletsPackage(loader);
            loadSessionPackage(loader);
            loadUtilPackage(loader);
            loadValvesPackage(loader);
            loadJavaxPackage(loader);
            loadConnectorPackage(loader);
            loadTomcatPackage(loader);
        }
          能够进每一个方法看下,它是载入了指定的一些类,注意这些类名是指定的。假设你放了自己的jar包在里面,那么它的载入就不是catalinaLoader完毕的。


          最后就是初始化catalinaDaemon对象了,从最后一段代码能够看出catalinaDaemon被赋值为org.apache.catalina.startup.Catalina的实例。

    而且通过反射调用调用了setParentClassLoader方法,參数是catalinaLoader。
        这里设置父载入器的用意是什么?以下是这种方法的源代码   

     public void setParentClassLoader(ClassLoader parentClassLoader) {
            this.parentClassLoader = parentClassLoader;
        }
         方法非常easy,看来问题不在这。在来看看Catalina的还有一个方法:

      public ClassLoader getParentClassLoader() {
            if (parentClassLoader != null) {
                return (parentClassLoader);
            }
            return ClassLoader.getSystemClassLoader();
        }

             事实上这里parentClassLoader属性不是说载入Catalina的类载入器的父类载入器。它仅仅是一个普通的属性。

            在来看看哪里调用了getParentClassLoader,在StandardServer中有这样一个方法:

      @Override
        public ClassLoader getParentClassLoader() {
            if (parentClassLoader != null)
                return (parentClassLoader);
            if (catalina != null) {
                return (catalina.getParentClassLoader());
            }
            return (ClassLoader.getSystemClassLoader());
        }
         然后他的下级组件StandardService:
      @Override
        public ClassLoader getParentClassLoader() {
            if (parentClassLoader != null)
                return (parentClassLoader);
            if (server != null) {
                return (server.getParentClassLoader());
            }
            return (ClassLoader.getSystemClassLoader());
        }
        与之相应的都有一个setParentClassLoader方法。
        engin容器也有这种方法。

    最后在WebappLoader中有个例如以下的方法:

     private WebappClassLoader createClassLoader()
            throws Exception {
    
            Class<?> clazz = Class.forName(loaderClass);
            WebappClassLoader classLoader = null;
    
            if (parentClassLoader == null) {
                parentClassLoader = container.getParentClassLoader();
            }
            Class<?

    >[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor<?> constr = clazz.getConstructor(argTypes); classLoader = (WebappClassLoader) constr.newInstance(args); return classLoader; }

       在这种方法中调用了org.apache.catalina.loader.WebappClassLoader的构造方法将容器container的parentClassLoader的属性最为classLoader的
    父类载入器。这里能够得出结论从 Server 》 service 》 engin(container) 》没一个级别都在尝试设置parentClassLoader的值,而parentClassLoader
    将作为WebappClassLoader的父类载入器。

    也就是说parentClassLoader是针对WebappClassLoader而言的,而每一级别都在尝试改动它。·



        如今已经介绍完了bootstrap的init方法,下一步是来介绍setAwait(true)方法的作用。

    通过反射设置了Catalina的await属性为true。Catalina成功启动后
    会通过检查该值来调用它的成员变量server的await方法:

    public void start() {
        ........
            if (await) {
                await();
                stop();
            }
        }
     public void await() {
    
            getServer().await();
    
        }
    Catalina的成员变量server是一个StandardServer对象,通过调用该对象的await方法,会让他一直监控server.xml配置文件里的这段配置:
    <Server port="8005" shutdown="SHUTDOWN">,所定义的端口发送过来的命令。


          最后看看start方法:

    public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();
    
        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);
    
    }

       start终于通过反射调用了catalinaDaemon(也就是Catalina)的start方法。

    (这里看到的多处位置是通过反射调用catalinaDaemon的方法。

    由于catalinaDaemon是一个object的引用指向的Catalina对象全部它仅仅能调用object对象的方法。想要调用Catalina的方法仅仅能通过反射。)

       总结:bootstrap的主要任务就是初始化commonLoader。catalinaLoader,sharedLoader。通过catalinaLoader载入所须要的类。

    初始化catalinaDaemon对象,调用它的start方法。

        疑问:bin/bootstrap.jar 和lib/catalina.jar中都有bootstrap,脚本调用的是bootstrap.jar中的main方法,bootstrap在初始三个类载入器后,

    载入类时并没有载入org.apache.catalina.startup包下的类。也就是说尽管两个jar包都含有bootstrap类,但仅仅是系统的类载入器载入了

    bin/bootstrap.jar里的bootstrap。而其它lib 文件夹下的全部的类都是有bootstrap里面的三个类载入器载入的。不清楚为什么这样做。



  • 相关阅读:
    JS实现添加至购物车功能
    python定制数据类型(继承与授权)两种方式
    模拟数据,控制账号
    绑定知识拓展
    面向对象之多态练习
    面向对象之继承与派生(学生管理系统)
    面向对象之组合(学生管理系统)
    一次小的上机试题
    面向对象之self classmethod staticmethod
    haproxy.conf文件操作(基于函数方式)
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5201010.html
Copyright © 2011-2022 走看看