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函數