程序员人生 网站导航

how tomcat works 读书笔记 八 载入器下

栏目:互联网时间:2014-11-18 08:29:45

载入类

我们看看之前的文章,这1节就从SimpleWrapper的loadServlet讲起。
SimpleWrapper.java以下(省略了try catch及其他部份代码)
public Servlet loadServlet() throws ServletException { ... String actualClass = servletClass; Loader loader = getLoader(); // Acquire an instance of the class loader to be used if (loader==null) { throw new ServletException("No loader."); } ClassLoader classLoader = loader.getClassLoader(); if (classLoader!=null) { classClass = classLoader.loadClass(actualClass); // Instantiate and initialize an instance of the servlet class itself servlet = (Servlet) classClass.newInstance(); // Call the initialization method of this servlet servlet.init(null); return servlet; }


 我们知道loader.getClassLoader();返回的就是webappclassloader类
 看了,关键的地方就是classLoader.loadClass(actualClass);
classLoader.loadClass(actualClass)终究调用的是以下的方法,resolve为false;

 下面的方法很长 但总而言之 也就以下几步

・ 所有加载过的类都要进行缓存,所以首先需要检查本地缓存。
・ 如果没法再本地缓存找到类,使用 java.langClassLoader 类的 findLoaderClass 方法在缓存查找类、
・ 如果在两个缓存中都没法找到该类,使用系统的类加载器避免从 J2EE 类中覆盖来的 web 利用程序。
・ 如果使用了安全管理器,检查该类是不是允许加载,如果该类不允许加载,则抛出 ClassNotFoundException 异常。
・ 如果要加载的类使用了委派标志或该类属于 trigger 包中,使用父加载器来加载类,如果父加载器为 null,使用系统加载器加载。
・ 从当前的源中加载类
・ 如果在当前的源中找不到该类并且没有使用委派标志,使用父类加载器。如果父类加载器为 null,使用系统加载器

・ 如果该类依然找不到,抛出 ClassNotFoundException 异常


public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { if (debug >= 2) log("loadClass(" + name + ", " + resolve + ")"); Class<?> clazz = null; // Don't load classes if class loader is stopped if (!started) { //若webappclassloader没有启动.... log("Lifecycle error : CL stopped"); throw new ClassNotFoundException(name); } // (0) Check our previously loaded local class cache clazz = findLoadedClass0(name); //看下面临时放进来的代码 等因而先在本地存储的已加载的类(hashmap)中找 if (clazz != null) { if (debug >= 3) log(" Returning class from cache"); if (resolve) resolveClass(clazz); return (clazz); } /* protected Class<?> findLoadedClass0(String name) { ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); if (entry != null) { return entry.loadedClass; } return (null); } */ // (0.1) Check our previously loaded class cache clazz = findLoadedClass(name); //再去虚拟机中去找 if (clazz != null) { if (debug >= 3) log(" Returning class from cache"); if (resolve) resolveClass(clazz); return (clazz); } // (0.2) Try loading the class with the system class loader, to prevent // the webapp from overriding J2SE classes try { //system 为系统类加载器 sun.misc.Launcher$AppClassLoader //先用系统加载器加载 //为何先用系统加载器 如果你写了1个类 全名为"java.lang.Object" 懂了吧? //大家可能会想 系统加载器不是甚么都能加载吗? 那还要后面的代码做甚么? //系统加载器的加载目录是甚么 大家看看就明白了 clazz = system.loadClass(name); if (clazz != null) { if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { // Ignore } //关于安全的问题 我没有研究过里面具体的代码 // (0.5) Permission to http://www.wfuyu.com/access/ this class when using a SecurityManager if (securityManager != null) { int i = name.lastIndexOf('.'); if (i >= 0) { try { securityManager.checkPackageAccess(name.substring(0,i)); } catch (SecurityException se) { String error = "Security Violation, attempt to use " + "Restricted Class: " + name; System.out.println(error); se.printStackTrace(); log(error); throw new ClassNotFoundException(error); } } } //delegate默许为false //filter 如果要加载的类是packageTrigers里面所限定的 就返回true //书上说packageTrigers 里面的包是不允许载入的 //可代码里没有体现不能加载呀? 谁知道为何,麻烦告知我1声 boolean delegateLoad = delegate || filter(name); System.out.println(delegate+" "+filter(name)+" ddd"); // (1) Delegate to our parent if requested if (delegateLoad) { if (debug >= 3) log(" Delegating to parent classloader"); ClassLoader loader = parent; System.out.println(loader+" loader"); if (loader == null) loader = system; try { clazz = loader.loadClass(name); if (clazz != null) { if (debug >= 3) log(" Loading class from parent"); if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { ; } } // (2) Search local repositories //至于repositories属性 是在webappLoader类start方法里 setRepositories()设定的 //使用的各个方法以下 //findClass findClassInternal findResourceInternal //在findResourceInternal中先加载WEB-INF/classes中的文件,然后加载WEB-INF/lib下的jar文件 //最后 resourceEntries.put(name, entry); //会把加载的enety放入resourceEntries中缓存起来 if (debug >= 3) log(" Searching local repositories"); try { clazz = findClass(name); if (clazz != null) { if (debug >= 3) log(" Loading class from local repository"); if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { ; } //系统加载器前面已加载过来 如果程序能运行到这里就说明系统加载器不行 为何还要再加载1遍 // (3) Delegate to parent unconditionally if (!delegateLoad) { if (debug >= 3) log(" Delegating to parent classloader"); ClassLoader loader = parent; if (loader == null) loader = system; try { clazz = loader.loadClass(name); if (clazz != null) { if (debug >= 3) log(" Loading class from parent"); if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { ; } } // This class was not found throw new ClassNotFoundException(name); }

利用程序

在上1节我们已说过,为了实现在文件变动后容器自动重载,需要在server.xml中配置
<Context path="/myApp" docBase="myApp"/>
现在我们还没有这个配置文件,替换的,在启动程序中添加以下代码:
Context context = new StandardContext(); // StandardContext's start method adds a default mapper context.setPath("/myApp"); context.setDocBase("myApp");


如果上面的代码在eclipse中运行,项目根目录下回产生1个myApp文件夹和work文件夹
在myApp文件夹中在设置WEB-INF/classes文件夹 里面放置前几篇博客中使用的两个servlet的class文件


另外要说明1点,自动重载的方法其实就是对照最后修改时间,详细代码大家看源码便可。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐