载入类

我们看看之前的文章,这一节就从SimpleWrapper的loadServlet讲起。

SimpleWrapper.java如下(省略了try catch及其他部分代码)

public Servlet loadServlet() throws ServletException {

    ...
    String actualClass = servletClass;
    Loader loader = getLoader();
    // Acquire an instance of the class loader to be used
    if (loader==null) {
      throw new ServletException("No loader.");
    }
    ClassLoader classLoader = loader.getClassLoader();

    if (classLoader!=null) {
        classClass = classLoader.loadClass(actualClass);

    // Instantiate and initialize an instance of the servlet class itself
      servlet = (Servlet) classClass.newInstance();

    // Call the initialization method of this servlet
      servlet.init(null);

    return servlet;
  }

我们知道loader.getClassLoader();返回的就是webappclassloader类

 看了,关键的地方就是classLoader.loadClass(actualClass);

classLoader.loadClass(actualClass)最终调用的是如下的方法,resolve为false;



 下面的方法很长 但总而言之 也就以下几步



· 所有加载过的类都要进行缓存,所以首先需要检查本地缓存。

· 如果无法再本地缓存找到类,使用 java.langClassLoader 类的 findLoaderClass 方法在缓存查找类、

· 如果在两个缓存中都无法找到该类,使用系统的类加载器避免从 J2EE 类中覆盖来的 web 应用程序。

· 如果使用了安全管理器,检查该类是否允许加载,如果该类不允许加载,则抛出 ClassNotFoundException 异常。

· 如果要加载的类使用了委派标志或者该类属于 trigger 包中,使用父加载器来加载类,如果父加载器为 null,使用系统加载器加载。

· 从当前的源中加载类

· 如果在当前的源中找不到该类并且没有使用委派标志,使用父类加载器。如果父类加载器为 null,使用系统加载器

· 如果该类仍然找不到,抛出 ClassNotFoundException 异常

    public Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException {
        if (debug >= 2)
            log("loadClass(" + name + ", " + resolve + ")");
        Class<?> clazz = null;

        // Don't load classes if class loader is stopped
        if (!started) {                           //若webappclassloader没有启动....
            log("Lifecycle error : CL stopped");
            throw new ClassNotFoundException(name);
        }

        // (0) Check our previously loaded local class cache
        clazz = findLoadedClass0(name);           //看下面临时放进来的代码 等于是先在本地存储的已加载的类(hashmap)中找
        if (clazz != null) {
            if (debug >= 3)
                log("  Returning class from cache");
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }
    /*
    protected Class<?> findLoadedClass0(String name) {

        ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
        if (entry != null) {
            return entry.loadedClass;
        }
        return (null);  

    }
    */

        // (0.1) Check our previously loaded class cache
        clazz = findLoadedClass(name);                  //再去虚拟机中去找
        if (clazz != null) {
            if (debug >= 3)
                log("  Returning class from cache");
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.2) Try loading the class with the system class loader, to prevent
        //       the webapp from overriding J2SE classes
        try {
            //system 为系统类加载器 sun.misc.Launcher$AppClassLoader
        //先用系统加载器加载
        //为什么先用系统加载器 如果你写了一个类 全名为"java.lang.Object" 懂了吧?
        //大家可能会想 系统加载器不是什么都能加载吗? 那还要后面的代码做什么?
        //系统加载器的加载目录是什么 大家看看就明白了
            clazz = system.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

    //关于安全的问题 我没有研究过里面具体的代码
        // (0.5) Permission to access this class when using a SecurityManager
        if (securityManager != null) {
            int i = name.lastIndexOf('.');
            if (i >= 0) {
                try {
                    securityManager.checkPackageAccess(name.substring(0,i));
                } catch (SecurityException se) {
                    String error = "Security Violation, attempt to use " +
                        "Restricted Class: " + name;
                    System.out.println(error);
                    se.printStackTrace();
                    log(error);
                    throw new ClassNotFoundException(error);
                }
            }
        }

    //delegate默认为false
    //filter 如果要加载的类是packageTrigers里面所限定的 就返回true
    //书上说packageTrigers 里面的包是不允许载入的
    //可代码里没有体现不能加载呀? 谁知道为什么,麻烦告知我一声
    //另外  就像前面几章http://localhost:8080/Primitive请求的PrimitiveServlet
    // delegate为false, filter(name)也是false
      boolean delegateLoad = delegate || filter(name);

        System.out.println(delegate+"  "+filter(name)+"  ddd");
        // (1) Delegate to our parent if requested
        if (delegateLoad) {
            if (debug >= 3)
                log("  Delegating to parent classloader");
            ClassLoader loader = parent;
            System.out.println(loader+"   loader");
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (debug >= 3)
                        log("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        // (2) Search local repositories
    //至于repositories属性 是在webappLoader类start方法里 setRepositories()设定的
    //使用的各个方法如下
    //findClass  findClassInternal findResourceInternal
    //在findResourceInternal中先加载WEB-INF/classes中的文件,然后加载WEB-INF/lib下的jar文件
    //最后 resourceEntries.put(name, entry);
    //会把加载的enety放入resourceEntries中缓存起来
        if (debug >= 3)
            log("  Searching local repositories");
        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (debug >= 3)
                    log("  Loading class from local repository");
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            ;
        }

    //系统加载器前面已经加载过来 如果程序能运行到这里就说明系统加载器不行 为什么还要再加载一遍
        // (3) Delegate to parent unconditionally
        if (!delegateLoad) {
            if (debug >= 3)
                log("  Delegating to parent classloader");
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (debug >= 3)
                        log("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        // This class was not found
        throw new ClassNotFoundException(name);

    }

应用程序

在上一节我们已经说过,为了实现在文件变动后容器自动重载,需要在server.xml中配置

<Context path="/myApp" docBase="myApp"/>

现在我们还没有这个配置文件,替代的,在启动程序中添加如下代码:

Context context = new StandardContext();
// StandardContext's start method adds a default mapper
context.setPath("/myApp");
context.setDocBase("myApp");

如果上面的代码在eclipse中运行,项目根目录下回产生一个myApp文件夹和work文件夹

在myApp文件夹中在设置WEB-INF/classes文件夹 里面放置前几篇博客中使用的两个servlet的class文件





另外要说明一点,自动重载的方法其实就是比照最后修改时间,详细代码大家看源码即可。

how tomcat works 读书笔记 八 载入器下的更多相关文章

  1. How Tomcat Works 读书笔记 八 载入器 上

    Java的类载入器 详细资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf1233 ...

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

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

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

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

  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 上

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

  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. 网络爬虫框架Scrapy简介

    作者: 黄进(QQ:7149101) 一. 网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本:它是一个自动提取网页的程序,它为搜索引擎从万维 ...

  2. 没事不要在for循环期间增减迭代序列的成员

    >>> arr=[4, 4, 9, 7, 7] >>> for i,a in enumerate(arr): arr.pop(i) print(i,a) 4 0 4 ...

  3. activiti实战系列 activiti连线

    11:连线 11.1:流程图 注意:如果将流程图放置在和java类相同的路径,需要配置: 11.2:部署流程定义+启动流程实例 11.3:查询我的个人任务 11.4:完成任务 说明: 1)使用流程变量 ...

  4. Compass 更智能的搜索引擎(2)--进阶

    经过了Compass 更智能的搜索引擎(1)–入门的学习,想必对于Compass的使用有了更深的认识了吧.下面谈点更加切合实际开发的东西.那就是CRUD. 面向对象的分页 dao层实现 代码释义 优点 ...

  5. Windows安装和使用fftw

    FFTW是一个比较快的.非常出名的一个DFT的开源库. 本文探索安装和配置FFTW,用Visual Studio 2008来使用fftw. 第一步:下载最新的fftw库 这一步很简单,只要在googl ...

  6. memcached实战系列(三)memcached命令使用

    memcached命令的使用,在这里我们最好了解一下命令的含义,对命令有一个大致的了解,在了解的基础上进行使用.这里的命名是常用的crud命令的演示. 1.1.1. memcached命令的格式 标准 ...

  7. Spring开发环境搭建教程

    Spring开发环境搭建 JDK7以上版本 eclispe for j2ee 4.0以上版本 Spring frameWorks 3.0以上版本 至于前两个我们就不介绍,直接百度就可以了,对于Spri ...

  8. Android 四种常见的线程池

    引入线程池的好处 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 我们来看一下线程池的简单的构造 public ThreadPoolExec ...

  9. INV 调试: 如何获取库存物料事务处理调试信息

     1. 按如下方式设置系统配置文件值: 系统配置文件值 地点/用户/应用/职责层配置文件值 --汇总 FND: 启用调试日志   是 FND:调试日志层级   陈述 INV: 调试跟踪: 是 IN ...

  10. oracle对大对象类型操作:blob,clob,nclob

     1.基本介绍 Oracle和plsql都支持lob(large object) 类型,用来存储大数量数据,如图像文件,声音文件等.Oracle 9i realse2支持存储最大为4g的数据,or ...