Java虚拟机(JVM)的动态类加载(Class Loading)

来源:互联网 发布:指甲油 知乎 编辑:程序博客网 时间:2024/05/17 06:13
<script type="text/javascript">google_ad_client = "pub-8800625213955058";/* 336x280, 创建于 07-11-21 */google_ad_slot = "0989131976";google_ad_width = 336;google_ad_height = 280;//</script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>1.介绍 Class Loaders是动态加载Java类与Resource的一种机制。它支持Laziness,type-safe linkage,user-defined extensibility和multiple communicating namespaces这4种特性。l Lazy loading:Class只有在需要的时候才加载。这样减少了内存使用量,能提高系统反映速度;l Type-safe linkage:动态类加载不会破坏JVM的类型安全;l User-definable class loading policy:开发者可以自定义的类加载器,控制动态类加载过程;l Multiple namespaces:JVM允许使用不同的类加载器加载相同的Class名称,但不同内容的类。Class Loaders早在JDK1.0时就已存在,最开始的目的是使HotJava浏览器能加载Applet。从那以后,动态类加载机制被广泛应用到其他方面,例如web application server中Servlets的加载。class loader在JDK 1.0,1.1版本存在的缺陷,已经在JDK 1.2解决,其缺陷主要是编写不正确的Class Loader会造成类型安全问题。2.Class LoadersClass Loader的目的是动态加载Java类和Resource。Java类是平台无关的,标准的,具有规范二进制文件格式的。class文件有编译器生成,可以被任何一中JVM加载。Java类的表现形式不仅只有.class文件,还可以为内存buffer,或是网络数据流。JVM执行class文件内的Byte code。但是Byte code不是class文件的全部内容,class文件内还包含符号表,表示类,属性和方法名,以及类内引用到其他类,属性,和方法名。例如下面的类 class C{ void f(){ D d=new D(); } }类文件内类C引用D。为了能让JVM知道D类是什么,JVM必须要先load D的class file并创建D class对象。JVM使用类加载器加载类文件,并创建Class对象。类加载器都是ClassLoader的子类实例。ClassLoader.loadClass方法通过获得一个类名,返回一个Class对象,表示该类的类型。上面的代码里,假设C被类加载器L加载,则L是C的加载器。JVM将使用L加载所有被C引用到的其他Java类。如果D还没有被加载,L将加载D: L.loadClass(“D”)当D已经被加载,JVM就可以创建D的一个对象实例。一个Java应用程序可以使用不同类型的类加载器。例如Web Application Server中,Servlet的加载使用开发商自定义的类加载器, java.lang.String在使用JVM系统加载器,Bootstrap Class Loader,开发商定义的其他类则由AppClassLoader加载。在JVM里由类名和类加载器区别不同的Java类型。因此,JVM允许我们使用不同的加载器加载相同namespace的java类,而实际上这些相同namespace的java类可以是完全不同的类。这种机制可以保证JDK自带的java.lang.String是唯一的。ClassLoader子类需要重载loadClass方法以实现用户自己的类加载方式,下面是自定义一个类加载器例子:package org.colimas.webapp; import java.io.File;import java.io.IOException;import java.net.URL;import java.net.URLClassLoader;import java.util.StringTokenizer; /** *类加载器加载Servlet,URLClassLoader是ClassLoader的一个子类,可以通过URL加载Java类或其它资源。 * @author 趙磊 * */public class WebAppClassLoader extends URLClassLoader { private ClassLoader _parent; public WebAppClassLoader(ClassLoader parent) { super(new URL[0], parent); _parent=parent; if (parent==null) throw new IllegalArgumentException("no parent classloader!"); } //追加一个Class Path。 public void addClassPath(String classPath) throws IOException{ if (classPath == null) return; StringTokenizer tokenizer= new StringTokenizer(classPath, ",;"); while (tokenizer.hasMoreTokens()) { URL url=null; File file=new File(tokenizer.nextToken()).getCanonicalFile(); url=file.toURI().toURL(); addURL(url); } } //加载类 public synchronized Class loadClass(String name) throws ClassNotFoundException { return loadClass(name,false); } protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c= findLoadedClass(name); ClassNotFoundException ex= null; if (c == null && _parent!=null ){ try{ c= _parent.loadClass(name); }catch (ClassNotFoundException e){ ex= e; } } if (c == null){ try{ c= this.findSystemClass(name); }catch (ClassNotFoundException e){ ex= e; } } if (c == null) throw ex; if (resolve) resolveClass(c); return c; }}loadClass方法中使用findLoadedClass方法检查类是否已经被加载。该方法是Native方法,实现在JVM的ClassLoader.c文件内的Java_java_lang_ClassLoader_findLoadedClass函数。如果返回为null,则表示类还没有被加载,于是在其Parent类加载器重寻找_parent.loadClass,如果仍然返回null,则要在系统中查找,findSystemClass,如果仍然没有,则抛出异常。我们要确保多线程在同一时间只能加载一次,因此需要synchronized。通常我们需要动态更新一个Class。例如一个Servlet实现发生变化时,我们希望不是重启服务器而是Reload。下面的类ServletWrapper提供了一个Servlet Reload的实现方法:package org.colimas.webapp; import javax.servlet.Servlet;import javax.servlet.ServletConfig;import javax.servlet.ServletException; /** * @author 趙磊 * */public class ServletWrapper { private Servlet theServlet; private Class servletClass; private ServletConfig config; private String _servletname; public ServletWrapper(ServletConfig config){ this.config=config; } public Servlet getServlet() throws ServletException{ synchronized (this) { destroy(); try { WebAppClassLoader loader=new WebAppClassLoader(this.getClass().getClassLoader()); String name=getServletName(); servletClass = loader.loadClass(name); theServlet = (Servlet) servletClass.newInstance(); } catch( ClassNotFoundException ex1 ) { } catch( InstantiationException ex ) { }catch(IllegalAccessException ex2){ } theServlet.init(config); } return theServlet; } public void destroy() { if (theServlet != null) { theServlet.destroy(); } } protected String getServletName(){ return _servletname; }}getServlet()获得一个Servlet对象。首先创建一个新的Servlet类加载器。loader.loadClass加载最新的Servlet,servletClass.newInstance()实例化新的Servlet对象,并theServlet.init(config);让它运行起来。这种方法只有在不改变Servlet的接口时有效的。如果你要加载的类不实现任何接口,那么就不能在ServletWrapper直接使用该类名。而是定义为Object theServlet,并且theServlet = servletClass.newInstance();,而theServlet.init(config);也不得不改写为:Method m= servletClass.getMethod(“init”,…);m.invoke(theServlet,…); 3. Type-safe Linkage和Namespace一致性 JVM使用loaded class cache保存class名和加载该class的类加载器。当JVM通过loadClass获得class之后,它执行以下操作:l 检查传给loadClass的类名是否和真实类名一致;l 如果一致,则保存到loaded class cache里。ClassLoader.findLoadedClass就是在loaded class cache查找class是否存在的。为了保证Type-safe,Sun公司做了很多工作,目前也有不止一个解决方案。例如,增加约束规则(Contraint Rule)等。
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 贱媛媛 想入媛媛 媛媛 啊媛 金智媛 苏充柳媛 媛媛幼儿故事 媛怎么读 任袁媛 郑媛媛雅照门全集3000张 媛助app 媛拼音 苏允柳媛免费 媛的拼音 娇媛卫幽 春媛馆app 新媛论坛 想入媛媛全文免费阅读 想入媛媛目录 小正和林媛王琴全文免费阅读 媛凤 媛的繁体字 媛字的含义 媛怎么组词 媛几画 媛媛卫生巾 媛读音 媛是什么意思 媛媛的意思 媛的读音 媛字 媛媛酱 媛媛回家全文阅读 媛的意思 媛有几画 奇迹媛媛 媛怎么读音 女友媛媛 媛的拼音怎么写 媛媛的成长日记gtss