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