Tomcat源码解读:ClassLoader的计划

         Tomcat是一个经的web
server,学习tomcat的源码对于咱们是发非常可怜的增援的。前一段时间了解了tomcat的做事之大致流程,对自身的新工作有矣充分酷的扶植。刚读了ClassLoader(学习classloader的初衷源于公司产品的一个bug),也拿自本着classloaderp写成了平等首博客。为了对ClassLoader有双重多之知,现在即使来探Tomcat
6 的ClassLoader设计。

        
之前经过对tomcat的启动过程、tomcat处理request的长河进展简要的打听,了解tomcat的依次零部件及其功能。在当下片只经过遭到,都发生ClassLoader的阴影,所以今天依然由当下简单个点下手,来打听Tomcat
如何运用ClassLoader。

 

StandardClassLoader

Bootstrap.main()方法大概点说不怕是推行4个措施:init , setAwait, load,
start。

init

public void init()
        throws Exception
    {

        // Set Catalina path
        setCatalinaHome();
        setCatalinaBase();

        initClassLoaders();

        Thread.currentThread().setContextClassLoader(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;

    }

每当init方法中调用首先initClassLoader方法来初始化Tomcat的ClassLoader模块,然后是采用刚由定义类加载器加载catalinaLoader
来加载org.apache.catalina.startup.Catalina
类。接下来是调用Catalina中之setParentClassLoader方法。

 

那么便看initClassLoader中将Tomcat的ClassLoader模块初始化成什么体统的:

private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            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);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
}

 

 

此间实在就算是创建了3独ClassLoader,分别是commonLoader, catalinaLoader,
sharedLoader。而事实上它们之间是发生及时某种关联的:

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

也就是说启动过程初始化后的ClassLoader模型为:

Java 1

里面顶部的3单classLoader对象都是因为JDK提供的。commonLoader, catalinaLoader,
sharedLoader它们三独出一个一块之名:StandardClassLoader。

bootstrapClassLoader是加载java_home/jre/lib目录下的独家jar包(不是任何)

extClassLoader是加载java_home/jre/lib/ext目录下之jar包

AppClassLoader是加载classpath中指定的jar包

于catalina.properties文件被虽然指出了及时3只ClassLoader默认的加载路径。

common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar
server.loader=
shared.loader=

其一文件是以jar包中之,在利用tomcat时凡无可以改的。如果想要修改默认的加载路径,该怎么处置也?可以在catalina.config配置

想念如果了解是什么原因,可以参见CatalinaProperties类的兑现。

 

点说了Bootstrap的main方法吃实际就是是调用了4只道init,setAwait, start,
load,除了init外,另外3个措施其实就算是调用Catalina对象的对应的setAwait,start,
load方法。

自从init方法的贯彻中,可以掌握,在Bootstrap类中,除了Catalina类是出于catalinaClassLoader加载的外,其余的切近都是JDK提供的ClassLoader加载的。也就是说根据上节上的情,Catalina类在现阶段类Bootstrap类中凡是勿能够一直调用的。然而这里而如果调用Catalina中之措施,我当上节的测试中,采取的是另外启动一个线程来化解的。今天虽来探视Tomcat中怎么样解决这样的采用场景的:

 

1)init中调用Catalina的setParentClassLoader方法

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

2) setAwait中调用catalina的setAwait方法

public void setAwait(boolean await)
        throws Exception {

        Class paramTypes[] = new Class[1];
        paramTypes[0] = Boolean.TYPE;
        Object paramValues[] = new Object[1];
        paramValues[0] = new Boolean(await);
        Method method = 
            catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
        method.invoke(catalinaDaemon, paramValues);

    }

3)start调用catalina的start方法

public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }

4)load调用catalina的load方法

private void load(String[] arguments)
        throws Exception {

        // Call the load() method
        String methodName = "load";
        Object param[];
        Class paramTypes[];
        if (arguments==null || arguments.length==0) {
            paramTypes = null;
            param = null;
        } else {
            paramTypes = new Class[1];
            paramTypes[0] = arguments.getClass();
            param = new Object[1];
            param[0] = arguments;
        }
        Method method = 
            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        if (log.isDebugEnabled())
            log.debug("Calling startup class " + method);
        method.invoke(catalinaDaemon, param);

    }

其还是用反射来处理。

现总的来说,要是化解由于不同classLoader加载器加载的接近之前的法门调用,就生出2种植处理方案了:

方案一:另启动一个线程

方案二:使用反射。

 

Catalina是由于catalinaClassLoader加载的,Tomcat启动过程会拿Tomcat的系组件加载并初始化,而这些经过的输入还在Catalina中。所以呢Tomcat中绝对在有些零件应当都是出于catalinaClassLoader加载的。这句话说的也许略满,不过呢,我这么说呢是发出案由之:

于init方法吃生出这么一个历程:SecurityClassLoad.securityClassLoad(catalinaLoader);

 

下面来探视是历程的本来面目:

public static void securityClassLoad(ClassLoader loader)
        throws Exception {

        if( System.getSecurityManager() == null ){
            return;
        }

        loadCorePackage(loader);
        loadLoaderPackage(loader);
        loadServletsPackage(loader);
        loadSessionPackage(loader);
        loadUtilPackage(loader);
        loadJavaxPackage(loader);
        loadCoyotePackage(loader);
        loadHttp11Package(loader);
        loadTomcatPackage(loader);
}

private final static void loadCorePackage(ClassLoader loader)
        throws Exception {
        String basePackage = "org.apache.catalina.";
        loader.loadClass
            (basePackage +
             "core.ApplicationContextFacade$1");
        loader.loadClass
            (basePackage +
             "core.ApplicationDispatcher$PrivilegedForward");
        loader.loadClass
            (basePackage +
             "core.ApplicationDispatcher$PrivilegedInclude");
        loader.loadClass
            (basePackage +
             "core.ContainerBase$PrivilegedAddChild");
        loader.loadClass
            (basePackage +
             "core.StandardWrapper$1");
        loader.loadClass
            (basePackage +
              "core.ApplicationHttpRequest$AttributeNamesEnumerator");
    }

securityClassLoad(ClassLoader
loader)采用了伪装(facade)模式来加载各个类。这里只排有了loadCorePackage的兑现。其它方式的贯彻与之是一点一滴一致的。所以地方
我才说Tomcat中绝对在有些零件应当都是由于catalinaClassLoader加载的。

还要依据是方式,也足以看,如加载中类,要为此外表类以及中类类名之间加上$

 

 

===============================================================================

WebappClassLoader

面说的骨子里就是是Tomcat中之StandardClassLoader,Tomcat中还有雷同种植WebappClassLoader。根据名字就可以看出来,这个ClassLoader是用来加载各个Web
Application而规划之。Tomcat的依次零部件中同Web
Application有对许提到之,也不怕是StandardContext。为何这么说啊?我们以Web应用中行使的ServletConext(Java
EE的标准API)在Tomcat中由ApplicationContext来贯彻,而ApplicationContext其实就是StandardContext的寄托。

 

这个Classloader是用来加载web应用程序中的类。这个仿佛后会时有发生专门询问一下。

 

相关文章