servlet解析演进(6)-类加载器(2)

web类加载器WebappClassLoader、WebappLoader。他们俩WebappLoader是领导。webClassLoader只负责加载类这份工作,而webappLoader除了有webClassLoader实例之外还拥有容器等信息,能做些"外交"工作。
WebappLoader类的start方法被调用的时候,将会完成下面几项重要任务
(1)创建一个类加载器
(2) 设置库
(3) 设置类路径
(4) 设置访问权限
(5) 开启一个新线程用来进行自动重载

public void start() throws LifecycleException {
    // Validate and update our current component state
//webapploader是否已经启动了,启动再起会跑错
    if (started)
        throw new LifecycleException
            (sm.getString("webappLoader.alreadyStarted"));
//debug模式打印信息    
if (debug >= 1)
    log(sm.getString("webappLoader.starting"));
//监听器触发START_EVENT事件
    lifecycle.fireLifecycleEvent(START_EVENT, null);
    started = true;
//空容器,不启动类加载器
    if (container.getResources() == null)
        return;
    // 为JNDI协议注册一个流处理工厂
    URLStreamHandlerFactory streamHandlerFactory =
        new DirContextURLStreamHandlerFactory();
    try {
        URL.setURLStreamHandlerFactory(streamHandlerFactory);
    } catch (Throwable t) {
        // Ignore the error here.
    }
    // 创建一个类加载器
    try {
        classLoader = createClassLoader();
        classLoader.setResources(container.getResources());
        classLoader.setDebug(this.debug);
        classLoader.setDelegate(this.delegate);
        for (int i = 0; i < repositories.length; i++) {
            classLoader.addRepository(repositories[i]);
        }
        //设置库
        setRepositories();
         //设置类路径
        setClassPath();
         // 设置访问权限
        setPermissions();
        
        if (classLoader instanceof Lifecycle)
            ((Lifecycle) classLoader).start();
        // 为目录上线文绑定webapp类的类加载器
        DirContextURLStreamHandler.bind
            ((ClassLoader) classLoader, this.container.getResources());
    } catch (Throwable t) {
        throw new LifecycleException("start: ", t);
    }
 // 包访问是否合法化判断
    validatePackages();  
//开启一个新线程用来进行自动重载
    if (reloadable) {
        log(sm.getString("webappLoader.reloading"));
        try {
        
            threadStart();
        } catch (IllegalStateException e) {
            throw new LifecycleException(e);
        }
    }
}
(1)创建一个类加载器
private WebappClassLoader createClassLoader()
    throws Exception {
//加载类WebappClassLoader
    Class clazz = Class.forName(loaderClass);
    WebappClassLoader classLoader = null;
//没有父类加载器就生成实例
    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;
}
(2) 为加载器WebappClassLoader实例设置库
       if (copyJars) {
                    if (!copy(jarResource.streamContent(),
                              new FileOutputStream(destFile)))
                        continue;
                }
               //获取jar包,并将其放置到
                JarFile jarFile = new JarFile(destFile);
                //为加载进来的包做处理,便于查找类是否被修改
                classLoader.addJar(filename, jarFile, destFile);
            }
        } catch (NamingException e) {
            // Silent catch: it's valid that no /WEB-INF/lib directory
            // exists
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
(3) 设置类路径
//jsp的解析器Jasper依赖classpath。将上下文属性正确设置到类路径上
private void setClassPath() {
    // Validate our current state information
    if (!(container instanceof Context))
        return;
    ServletContext servletContext =
        ((Context) container).getServletContext();
    if (servletContext == null)
        return;
    StringBuffer classpath = new StringBuffer();
    // Assemble the class path information from our class loader chain
    ClassLoader loader = getClassLoader();
    int layers = 0;
    int n = 0;
    while ((layers < 3) && (loader != null)) {
        if (!(loader instanceof URLClassLoader))
            break;
        URL repositories[] =
            ((URLClassLoader) loader).getURLs();
        for (int i = 0; i < repositories.length; i++) {
            String repository = repositories[i].toString();
            if (repository.startsWith("file://"))
                repository = repository.substring(7);
            else if (repository.startsWith("file:"))
                repository = repository.substring(5);
            else if (repository.startsWith("jndi:"))
                repository =
                    servletContext.getRealPath(repository.substring(5));
            else
                continue;
            if (repository == null)
                continue;
            if (n > 0)
                classpath.append(File.pathSeparator);
            classpath.append(repository);
            n++;
        }
        loader = loader.getParent();
        layers++;
    }
//存储类路径到servlet上下文属性中
    servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
                                classpath.toString());
}
(4) 设置访问权限
 
 private void setPermissions() {
//如果没有配置security则返回
        if (System.getSecurityManager() == null)
            return;
        //如果上下文不是容器子类则返回
        if (!(container instanceof Context))
            return;
          //获取servlet上下文
               ServletContext servletContext =
            ((Context) container).getServletContext();
        //找到工作控件的路径
         File workDir =
            (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
        if (workDir != null) {
            try {
                String workDirPath = workDir.getCanonicalPath();
                //为类加载器添加工作空间路径为读、写可访问权限
                classLoader.addPermission
                    (new FilePermission(workDirPath, "read,write"));
                //为类加载器添加工作空间中文件有读写删除的访问权限
                classLoader.addPermission
                    (new FilePermission(workDirPath + File.separator + "-",
                                        "read,write,delete"));
            } catch (IOException e) {
                // Ignore
            }
        }
        try {
               //项目根路径
            URL rootURL = servletContext.getResource("/");
            classLoader.addPermission(rootURL);
              //项目的绝对路径
            String contextRoot = servletContext.getRealPath("/");
            if (contextRoot != null) {
                try {
                    contextRoot =
                        (new File(contextRoot)).getCanonicalPath()
                        + File.separator;
                    //访问权限
                    classLoader.addPermission(contextRoot);
                } catch (IOException e) {
                    // Ignore
                }
            }
         ///WEB-INF/classes/  路径访问权限添加
            URL classesURL =
                servletContext.getResource("/WEB-INF/classes/");
            if (classesURL != null)
                classLoader.addPermission(classesURL);
        ///WEB-INF/lib/ 路径访问权限添加
            URL libURL = servletContext.getResource("/WEB-INF/lib/");
            if (libURL != null) {
                classLoader.addPermission(libURL);
            }
            if (contextRoot != null) {
                if (libURL != null) {
                    File rootDir = new File(contextRoot);
                    //项目的WEB-INF/lib/路径的权限
                    File libDir = new File(rootDir, "WEB-INF/lib/");
                    String path = null;
                    try {
                        path = libDir.getCanonicalPath() + File.separator;
                    } catch (IOException e) {
                    }
                    if (path != null)
                        classLoader.addPermission(path);
                }
            } else {
                if (workDir != null) {
                    if (libURL != null) {
                        //项目的WEB-INF/lib/路径的权限
                        File libDir = new File(workDir, "WEB-INF/lib/");
                        String path = null;
                        try {
                            path = libDir.getCanonicalPath() + File.separator;
                        } catch (IOException e) {
                        }
                        classLoader.addPermission(path);
                    }
                    if (classesURL != null) {
                        // 项目空间的WEB-INF/lib/路径的权限
                        File classesDir =
                            new File(workDir, "WEB-INF/classes/");
                        String path = null;
                        try {
                            path = classesDir.getCanonicalPath()
                                + File.separator;
                        } catch (IOException e) {
                        }
                        classLoader.addPermission(path);
                    }
                }
            }
        } catch (MalformedURLException e) {
        }
    }
(5) 开启一个新线程用来进行自动重载
private void threadStart() {
    // Has the background thread already been started?
    if (thread != null)
        return;
    // Validate our current state
    if (!reloadable)
        throw new IllegalStateException
            (sm.getString("webappLoader.notReloadable"));
    if (!(container instanceof Context))
        throw new IllegalStateException
            (sm.getString("webappLoader.notContext"));
    // Start the background thread
    if (debug >= 1)
        log(" Starting background thread");
    threadDone = false;
    threadName = "WebappLoader[" + container.getName() + "]";
    thread = new Thread(this, threadName);
    //启动WebappLoader类,将其设置为后台线程。
    thread.setDaemon(true);
    thread.start();
}
public void run() {
    if (debug >= 1)
        log("BACKGROUND THREAD Starting");
    // Loop until the termination semaphore is set
    while (!threadDone) {
        // Wait for our check interval
        threadSleep();
        if (!started)
            break;
        try {
            // 没有属性修改则继续,
            if (!classLoader.modified())
                continue;
        } catch (Exception e) {
            log(sm.getString("webappLoader.failModifiedCheck"), e);
            continue;
        }
        // Handle a need for reloading
        notifyContext();
        break;
    }
private void notifyContext() {
    WebappContextNotifier notifier = new WebappContextNotifier();
    (new Thread(notifier)).start();
}
protected class WebappContextNotifier implements Runnable {
    /**
     * Perform the requested notification.
     */
    public void run() {
//调用容器reload方法重启服务器环境
        ((Context) container).reload();
    }
}



参考文献:


http://blog.csdn.net/gjanyanlig/article/details/6818655

http://www.cnblogs.com/xing901022/p/4574961.html

http://blog.csdn.net/dc_726/article/details/11873343

http://lovnet.iteye.com/blog/1825322

http://www.cnblogs.com/ITtangtang/p/3978102.html

http://blog.sina.com.cn/s/blog_4fe01e630100gu3x.html

http://www.ibm.com/developerworks/cn/java/j-dclp1/

http://www.tuicool.com/articles/NrI7NrN


你可能感兴趣的:(servlet解析演进(6)-类加载器(2))