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

载入类

我们看看之前的文章,这一节就从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 里面的包是不允许载入的
    //可代码里没有体现不能加载呀? 谁知道为什么,麻烦告知我一声
        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文件

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

时间: 2024-08-29 12:02:58

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

How Tomcat Works 读书笔记 八 载入器

Java的类载入器 详细资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf123321/article/details/40431297 首先说明两个术语 仓库(repository),表示类加载器会在哪里搜索要载入的类; 资源(resource),知道一个类载入器中的DirContext对象,它的文件跟路径指的就是上下文的文件跟路径. 在tomcat中,我们使用了自定义载入器,

How tomcat works 读书笔记十二 StandardContext 下

对重载的支持 tomcat里容器对重载功能的支持是依靠Load的(在目前就是WebLoader).当在绑定载入器的容器时 public void setContainer(Container container) { ... // Register with the new Container (if any) if ((this.container != null) && (this.container instanceof Context)) { setReloadable( ((Co

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

app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/article/details/39378157) 回顾我们上一章,我们开发了一个最最简单的web服务器,它可以使用户访问服务器内的静态资源.当然这是远远不够的,在这一节里,我们就试着让服务器在能相应静态资源的基础上继续支持servlet. servlet接口 javax.servlet.Servlet接口

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

其实在第三章,就已经有了连接器的样子了,不过那只是一个学习工具,在这一章我们会开始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足以下几个要求 1 实现org.apache.cataline.Connector接口 2 负责创建实现了org.apache.cataline.Request接口的request对象 3 负责创建实现了org.apache.cataline.Response接口的response对象 这里默认的连接器的原理很简单,就是等待http请求,创建re

How tomcat works 读书笔记十二 StandardContext 上

在tomcat4中,StandardContext.java是最大的一个类,有117k.废话不说,开始分析吧. 其实要分析StandardContext,也就主要分析两个方法,一个start,一个invoke. 两个变量 这里首先咱们得说两个boolean型的变量available,configured. 先说available,它表示了StandardContext是否可用,初始值为false.若StandardContext启动成功,其值就变为true;另外各种原因都会导致StandardC

how tomcat works 读书笔记 十一 StandWrapper 上

方法调用序列 下图展示了方法调用的协作图: 这个是前面第五章里,我画的图: 我们再回顾一下自从连接器里 connector.getContainer().invoke(request, response); 这句代码运行之后发生的事情; 这是第五章的时序图,放在这一章同样适用... 我们仔细分析一下: 1首先连接器创建请求与响应对象; 2调用这行代码 connector.getContainer().invoke(request, response) (我们一StandContext为顶层容器)

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

一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让用户更方便的启动tomcat,还有批处理文件startup.bat(终于见到最顶层的模块了!!) Catalina 先说Catalina 它里面有一个Server组件(不懂的看第14章).同时在它的start方法中包含一个Digester对象(不懂的看第15章)用来解析conf/下的Server.x

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

在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的configured变量置为true.在这里我们看看完整版的ContextConfig都干了什么. 在tomcat的实际部署中,StandContext类的实际监听器是org.apache.catalina.startup.ContextConfig的实例. ContextConfig完成加载验证器阀,

How tomcat works 读书笔记十三 Host和Engine

Host Host是Context的父容器.如果想在一个tomcat上部署多个context就需要使用Host了.上下文容器的父容器是主机,但是可能有一些其它实现,没有必要的时候也可以忽略.不过在实践中,即使是一个Context,我们也使用了Host,为什么?后面我们再说. Host是个接口,里面有个map方法比较重要 /** * Return the Context that would be used to process the specified * host-relative requ