Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1528874
  • 博文数量: 3500
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 43870
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-03 20:31
文章分类

全部博文(3500)

文章存档

2008年(3500)

我的朋友

分类:

2008-05-04 19:16:01

一起学习
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 Loaders Class 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)等。 下载本文示例代码


Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)Java虚拟机(JVM)的动态类加载(Class Loading)
阅读(675) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~