Java的类载入器

详细资料见

http://blog.csdn.net/dlf123321/article/details/39957175

http://blog.csdn.net/dlf123321/article/details/40431297



首先说明两个术语

仓库(repository),表示类加载器会在哪里搜索要载入的类;

资源(resource),知道一个类载入器中的DirContext对象,它的文件跟路径指的就是上下文的文件跟路径。

在tomcat中,我们使用了自定义载入器,原因有三:

为了在载入器中指定某些规则;

为了缓存已经载入的类;

为了实现类的预载入;

Loader接口

在加载servlet及相关类的时候,需要遵守一些规则。例如,应用程序中的servelt只能引用部署在web-inf/classes目录下及其子目录下的类,只能访问web-inf/lib目录下的库。

我们在tomcat里说的载入器是指web应用程序载入器,而不仅仅是类载入器。(载入器里面有个类载入器!!!)

载入器应该实现org.apache.catalina.Loader接口,类载入器默认为WebappClassLoader。

package org.apache.catalina;

import java.beans.PropertyChangeListener;

public interface Loader {
    public ClassLoader getClassLoader();
    public Container getContainer();              //载入器通常与一个context级别的容器相联
    public void setContainer(Container container);
    public DefaultContext getDefaultContext();
    public void setDefaultContext(DefaultContext defaultContext);
    public boolean getDelegate();                 //Delegate 代表 委托
    public void setDelegate(boolean delegate);    //就是类加载器是否会把加载的任务委托给其父类加载器
    public String getInfo();
    public boolean getReloadable();               //表明是否支持载入器的自动重载
    public void setReloadable(boolean reloadable);
    public void addPropertyChangeListener(PropertyChangeListener listener);
    public void addRepository(String repository);
    public String[] findRepositories();
    public boolean modified();                     //如果容器中的一个或多个类被修改了 modified就会返回true
    public void removePropertyChangeListener(PropertyChangeListenerlistener);
}

默认情况下,在context的标准实现---org.apache.catalina.core.StandContext中是不支持自动重载的,因此要想开启自动重载功能,就需要在server.xml文件中添加一个Context元素,如下

<Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>

在我们这一节的程序中Catalina 提供了 org.apache.catalina.loader.WebappLoader 作为 Load 接口的实现。WebappLoader 对象包含一个org.apache.catalina.loader.WebappClassLoader 类的实例,该类扩展了Java.netURLClassLoader 类。

当与某个载入器相关联的容器需要使用某个servlet时,或者说就是要调用某个servlet的某个方法时,容器首先会调用载入器的getClassLoader()方法返回类载入器,然后再调用类载入器的loadClass()方法来加载这个servlet类。

uml图如下

WebAppLoader类

当webapploader类的start方法启动时,会完成以下几项工作:

1 创建一个类载入器

2 设置仓库

3 设置类路径

4 设置访问权限

5 启动一个新线程来支持自动重载 (在webapploader的run方法中)

创建类载入器

 private WebappClassLoader createClassLoader()
        throws Exception {

    //loadClass为字符串
    //默认为    private String loaderClass ="org.apache.catalina.loader.WebappClassLoader";
    //可通过setLoadClass方法更改
        Class<?> clazz = Class.forName(loaderClass);
        WebappClassLoader classLoader = null;

    //在构造WebAppLoader时 又构造函数的参数指定
        if (parentClassLoader == null) {
            // Will cause a ClassCast is the class does not extend WCL, but
            // this is on purpose (the exception will be caught and rethrown)
            classLoader = (WebappClassLoader) clazz.newInstance();
        } else {
            Class<?>[] argTypes = { ClassLoader.class };
            Object[] args = { parentClassLoader };
            Constructor<?> constr = clazz.getConstructor(argTypes);
            classLoader = (WebappClassLoader) constr.newInstance(args);
        }
        return classLoader;
    }

当然我们可以通过setLoadClass来改变类加载器的实现,不过

(WebappClassLoader) constr.newInstance(args);

所以,我们自定义的类也要继承WebappClassLoader。

设置仓库

调用setRepositories,设置WEB-ING/classes目录与WEB-INF/lib目录

设置类路径

和jasper JSP编译器有关

设置访问权限

setPermissions 可以设置类载入器访问相关路径的权限。例如只能访问WEB-INf/classes目录与WEB-INF/lib目录

开启新线程执行类的重新载入

 public void run() {

        if (debug >= 1)
            log("BACKGROUND THREAD Starting");

        // Loop until the termination semaphore is set
    //整段代码包含在while循环中
    //在前面threadDone已经被设置为false
    //直到程序关闭时,threadDone才会变为true
        while (!threadDone) {
            // Wait for our check interval
            threadSleep();

            if (!started)
                break;

            try {
                // Perform our modification check
                if (!classLoader.modified())
                    continue;
            } catch (Exception e) {
                log(sm.getString("webappLoader.failModifiedCheck"), e);
                continue;
            }

            // Handle a need for reloading
            notifyContext();
            break;

        }

        if (debug >= 1)
            log("BACKGROUND THREAD Stopping");

    }

    private void threadSleep() {          //让程序休眠一段时间 时间由checkInterval指定
        try {
            Thread.sleep(checkInterval * 1000L);
        } catch (InterruptedException e) {
            ;
        }
    }

checkInterval,是每隔若干秒来检查一次容器中的类是否有更改!

一旦有更改classLoader.modified()会返回true,直接调用notifyContext();

 private void notifyContext() {
        WebappContextNotifier notifier = new WebappContextNotifier();
        (new Thread(notifier)).start();
    }
protected class WebappContextNotifier implements Runnable {

        /**
         * Perform the requested notification.
         */
        public void run() {
            ((Context) container).reload();
        }
    }

WebappContextNotifier是webapploader的内部类。

这里重新启了一个线程,避免了拥塞。

WebappClassLoader类

该类继承自java.net.URLClassLoader类,后者我们在前面章节已经用过;

WebappClassLoader类的设计考虑了安全与优化两个方面。

WebappClassLoader 类不允许一些特定的类被加载。这些类被存储在一个 String 类型的数组中,现在仅仅有一个成员。

private static final String[] triggers = {

    "javax.servlet.Servlet" // Servlet API

};

另外在委派给系统加载器的时候,也不允许加载某些特殊的包的类或者它的子包:

private static final String[] packageTriggers = {
    "javax", // Java extensions
    "org.xml.sax", // SAX 1 & 2
    "org.w3c.dom", // DOM 1 & 2
    "org.apache.xerces", // Xerces 1 & 2
    "org.apache.xalan" // Xalan
};

类缓存

为了达到更好的性能,会缓存已经载入的类,这样一来下次在使用这个类的时候,就不用再起加载了。

缓存分两级,一级在本地执行,由webappclassloader实例来管理。

此外,java.lang.ClassLoader类也会维护一个Vector对象,保存已经载入的类,此时缓存由父类管理。



每个由WebappClassLoader载入的类,都视为资源。是org.apache.catalina.loader.ResourceEntry类的实例,里面包含所代表的class文件的字节流,最后一次修改时间等等:

package org.apache.catalina.loader;
import java.net.URL;
import java.security.cert.Certificate;
import java.util.jar.Manifest;
public class ResourceEntry {
    public long lastModifled = -1;
    // Binary content of the resource.public byte[] binaryContent = null;
    public Class loadedClass = null;
    // URL source from where the object was loaded.
    public URL source = null;
    // URL of the codebase from where the object was loaded.
    public URL CodeBase = null;
    public Manifest manifest = null;
    public Certificate[] certificates = null;
}

所有缓存的源被存放在一个叫做 resourceEntries 的 HashMap 中,键值为载入的资源名称,所有找不到的资源都被放在一个名为 notFoundResources 的 HashMap 中。







至于真正的加载类,我们放在下一节说。

参考资料

http://my.oschina.net/xianggao/blog/70826

How Tomcat Works 读书笔记 八 载入器 上的更多相关文章

  1. how tomcat works 读书笔记 八 载入器下

    载入类 我们看看之前的文章,这一节就从SimpleWrapper的loadServlet讲起. SimpleWrapper.java如下(省略了try catch及其他部分代码) public Ser ...

  2. How Tomcat Works 读书笔记 八 加载器 上

    Java的类加载器 具体资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf1233 ...

  3. How tomcat works 读书笔记十二 StandardContext 上

    在tomcat4中,StandardContext.java是最大的一个类,有117k.废话不说,开始分析吧. 其实要分析StandardContext,也就主要分析两个方法,一个start,一个in ...

  4. how tomcat works 读书笔记(二)----------一个简单的servlet容器

    app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...

  5. how tomcat works 读书笔记四 tomcat的默认连接器

    事实上在第三章,就已经有了连接器的样子了,只是那仅仅是一个学习工具,在这一章我们会開始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足下面几个要求 1 实现org.apache ...

  6. How tomcat works 读书笔记十二 StandardContext 下

    对重载的支持 tomcat里容器对重载功能的支持是依靠Load的(在目前就是WebLoader).当在绑定载入器的容器时 public void setContainer(Container cont ...

  7. how tomcat works 读书笔记 十一 StandWrapper 上

    方法调用序列 下图展示了方法调用的协作图:  这个是前面第五章里,我画的图:  我们再回顾一下自从连接器里  connector.getContainer().invoke(request, resp ...

  8. How tomcat works 读书笔记十七 启动tomcat 上

    一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让 ...

  9. How tomcat works 读书笔记十五 Digester库 下

    在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的co ...

随机推荐

  1. SpriteKit塔防游戏动态改变防御塔价格标签的颜色

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 本篇blog在DinoDefense塔防游戏基础之上做一处小的 ...

  2. SQLite Select 语句(http://www.w3cschool.cc/sqlite/sqlite-select.html)

    SQLite Select 语句 SQLite 的 SELECT 语句用于从 SQLite 数据库表中获取数据,以结果表的形式返回数据.这些结果表也被称为结果集. 语法 SQLite 的 SELECT ...

  3. SSO 基于Cookie+fliter实现单点登录 实例解析(一)

    接上文,SSO的理论讲解,接下来实践实践! 1.使用Cookie解决单点登录 技术点: 1.设置Cookie的路径为setPath("/").即Tomcat的目录下都有效 2.设置 ...

  4. iOS开发之使用block块进行数据遍历的方法

    看了一篇文章,发现遍历数组.字典中的数据时,除了使用for循环外,还可以使用block块进行操作,瞬间感觉iOS的语言代码确实有点高大上的感觉,下面就简单的介绍一下这个方法. 首先是最基本的运用形式, ...

  5. 查看linux的进程到底用了多少内存

    1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有    (1). ps aux:      其中  VSZ(或VSS)列 表示,程序占用了多少虚拟内存.          ...

  6. java编程小记

    http://blog.csdn.net/pipisorry/article/details/51050189 很久没写java,什么都不会了,小记一下. 类型转换 字符串转int类型:Integer ...

  7. (八十)MapKit放置系统默认大头针和自定义大头针

    有关MapView的显示和定位在上一节已经说明,这一节说明如何在地图上放置大头针,以及设置点击大头针的视图. [系统默认大头针] mapView上放置大头针的方法是调用其addAnnotation:方 ...

  8. 深入分析Spring混合事务

    在ORM框架的事务管理器的事务内,使用JdbcTemplate执行SQL是不会纳入事务管理的. 下面进行源码分析,看为什么必须要在DataSourceTransactionManager的事务内使用J ...

  9. (NO.00004)iOS实现打砖块游戏(三):游戏主场景和砖块

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 制作墙体 首先在SpriteBuilder中新建Wall.ccb ...

  10. Docker教程:镜像构建和自动镜像构建dockerfile

    http://blog.csdn.net/pipisorry/article/details/50805379 Docker透过Dockerfile来记录建立Container映象文件的每一个步骤,可 ...