servlet解析演進(6)-類加載器(2)

web類加載器WebappClassLoader、WebappLoader。他們倆WebappLoader是領導。webClassLoader只負責加載類這份工做,而webappLoader除了有webClassLoader實例以外還擁有容器等信息,能作些"外交"工做。
WebappLoader類的start方法被調用的時候,將會完成下面幾項重要任務
(1)建立一個類加載器
(2) 設置庫
(3) 設置類路徑
(4) 設置訪問權限
(5) 開啓一個新線程用來進行自動重載
html

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();
    }
}



參考文獻:java


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

http://www.cnblogs.com/xing901022/p/4574961.html服務器

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

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

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

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

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

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

相關文章
相關標籤/搜索