载入类

我们看看之前的文章,这一节就从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. Unity 资源管理插件

    之所以写这个插件呢,就是为了方便整理项目中的资源文件,我记得之前好像也用了这么一个插件,但是也没去找,还是自己动手写一个吧,需要什么功能就看自己的需求. 在项目的过程中呢,已经写了一个插件来管理材质, ...

  2. Android必知必会-发布开源 Android 项目注意事项

    如果移动端访问不佳,请使用 –> Github版 1. 合理配置 .gitignore 文件 配置 .gitignore 可以排除一些非必要文件和保护保密信息,下面是在项目根目录下 .gitig ...

  3. 详解EBS接口开发之采购订单导入

    采购订单常用标准表简介 1.1   常用标准表 如下表中列出了与采购订单导入相关的表和说明: 表名 说明 其他信息 po.po_headers_all 采购订单头 采购订单号,采购类型,供应商,地点, ...

  4. JQuery插件使用之Validation 快速完成表单验证的几种方式

    JQuery的Validation插件可以到http://plugins.jquery.com/上去下载.今天来分享一下,关于这个插件的使用. 简易使用 这第一种方式可谓是傻瓜式的使用,我们只需要按照 ...

  5. Spark发展现状与战线

    前言 现今Spark正是风头正劲时,Spark本是UCBerkeley的AMPLab诞生的项目,后来捐赠给了Apache来管理源码和后续发展.今年从Apache孵化器终于孵化出了1.0版本.其对大数据 ...

  6. Java的多态及注意事项

    什么是多态: 多态不但能够改善代码的组织结构和可读性,还能够创建可扩展的程序.在Java中,所有的方法都是通过动态绑定实现多态的.将一个方法调用同一个方法主体关联起来被称作绑定.动态绑定的含义是在运行 ...

  7. 【DevOps敏捷开发动手实验】开源文档 v2015.2 stable 版发布

    Team Foundation Server 2015 Update 2版本终于在2周前的//Build 2016大会上正式发布了,借这个东风,小编也完成了[DevOps敏捷开发动手实验]开源文档的第 ...

  8. FORM当前状态分析

     变量  SYSTEM.RECORD_STATUS 确定当前记录状态.有四种返回值:CHANGED表示记录从数据库取来,并且该记录至少一个基表列被更新:INSERT表示给一个非取自数据库记录的基表 ...

  9. Android上下文菜单ContentView详解

    ContentView介绍 上下文菜单继承了android.view.Menu,因此我们可以像操作Options Menu那样给上下文菜单增加菜单项.上下文菜单与Options Menu最大的不同在于 ...

  10. java的list几种实现方式的效率(ArrayList、LinkedList、Vector、Stack),以及 java时间戳的三种获取方式比较

    一.list简介 List列表类,顺序存储任何对象(顺序不变),可重复. List是继承于Collection的接口,不能实例化.实例化可以用: ArrayList(实现动态数组),查询快(随意访问或 ...