zoukankan      html  css  js  c++  java
  • How Tomcat Works 读书笔记 八 加载器 上


    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
  • 相关阅读:
    linux在线安装jdk,tomcat,Nginx
    SpringAOP的实现方式
    Spring整合Mybatis
    基本sql语句
    解决No module named 'sklearn.cross_validation'
    虚拟机中安装redhat8操作系统
    【Linux命令】tcpdump抓包工具
    【Nodejs】Linux系统搭建Nodejs
    【SSL证书配置】tomcat实现SSL证书访问
    【SSL证书配置】腾讯云申请ssl证书,nginx+tomcat配置ssl证书
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6775004.html
Copyright © 2011-2022 走看看