`

classloader 三

    博客分类:
  • JVM
阅读更多

jvm classLoader architecture :

a, Bootstrap ClassLoader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作.

 

b, Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作

 

c, System ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作.

 

b, User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性.

 

类加载器的特性:

1, 每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
2, 为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 ” 双亲委派的加载链 ” 结构.


如下图:
java class loader

Class Diagram:
classloader 类图

类图中, BootstrapClassLoader是一个单独的java类, 其实在这里, 不应该叫他是一个java类。
因为, 它已经完全不用java实现了。

 

它是在jvm启动时, 就被构造起来的, 负责java平台核心库。(具体上面已经有介绍)

启动类加载实现 (其实我们不用关心这块, 但是有兴趣的, 可以研究一下 ):
bootstrap classLoader 类加载原理探索

 

自定义类加载器加载一个类的步骤 :

自定义类加载器加载一个类的步骤

 

ClassLoader 类加载逻辑分析, 以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:

 

Java代码  收藏代码
  1. // 检查类是否已被装载过   
  2. Class c = findLoadedClass(name);  
  3. if  (c ==  null  ) {  
  4.      // 指定类未被装载过   
  5.      try  {  
  6.          if  (parent !=  null  ) {  
  7.              // 如果父类加载器不为空, 则委派给父类加载   
  8.              c = parent.loadClass(name, false  );  
  9.          } else  {  
  10.              // 如果父类加载器为空, 则委派给启动类加载加载   
  11.              c = findBootstrapClass0(name);  
  12.          }  
  13.      } catch  (ClassNotFoundException e) {  
  14.          // 启动类加载器或父类加载器抛出异常后, 当前类加载器将其   
  15.          // 捕获, 并通过findClass方法, 由自身加载   
  16.          c = findClass(name);  
  17.      }  
  18. }  

 

用Class.forName加载类
Class.forName使用的是被调用者的类加载器来加载类的.
这种特性, 证明了java类加载器中的名称空间是唯一的, 不会相互干扰.

即在一般情况下, 保证同一个类中所关联的其他类都是由当前类的类加载器所加载的.

 

Java代码  收藏代码
  1. public   static  Class forName(String className)  
  2.      throws  ClassNotFoundException {  
  3.      return  forName0(className,  true  , ClassLoader.getCallerClassLoader());  
  4. }  
  5.    
  6. /** Called after security checks have been made. */   
  7. private   static   native  Class forName0(String name,  boolean  initialize,  
  8. ClassLoader loader)  
  9.      throws  ClassNotFoundException;  

 

上图中 ClassLoader.getCallerClassLoader 就是得到调用当前forName方法的类的类加载器

 

线程上下文类加载器
java默认的线程上下文类加载器是 系统类加载器(AppClassLoader).

 

Java代码  收藏代码
  1. // Now create the class loader to use to launch the application   
  2. try  {  
  3.     loader = AppClassLoader.getAppClassLoader(extcl);  
  4. catch  (IOException e) {  
  5.     throw   new  InternalError(  
  6. "Could not create application class loader"  );  
  7. }  
  8.    
  9. // Also set the context class loader for the primordial thread.   
  10. Thread.currentThread().setContextClassLoader(loader);  

 

以上代码摘自sun.misc.Launch的无参构造函数Launch()。

使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.

大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).

线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.

使java类加载体系显得更灵活.

 

随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,
在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择.

 

当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,
防止因为不同的类加载器, 导致类型转换异常(ClassCastException).

 

自定义的类加载器实现
defineClass(String name, byte[] b, int off, int len,ProtectionDomain protectionDomain)
是java.lang.Classloader提供给开发人员, 用来自定义加载class的接口.

使用该接口, 可以动态的加载class文件.

 

例如,
在jdk中, URLClassLoader是配合findClass方法来使用defineClass, 可以从网络或硬盘上加载class.

而使用类加载接口, 并加上自己的实现逻辑, 还可以定制出更多的高级特性.

 

比如,

一个简单的hot swap 类加载器实现:

 

 

Java代码  收藏代码
  1. import  java.io.File;  
  2. import  java.io.FileInputStream;  
  3. import  java.lang.reflect.Method;  
  4. import  java.net.URL;  
  5. import  java.net.URLClassLoader;  
  6.    
  7. /**  
  8. * 可以重新载入同名类的类加载器实现  
  9. *  
  10.    
  11. * 放弃了双亲委派的加载链模式.  
  12. * 需要外部维护重载后的类的成员变量状态.  
  13. *  
  14. * @author ken.wu  
  15. * @mail ken.wug@gmail.com  
  16. * 2007-9-28 下午01:37:43  
  17. */   
  18. public   class  HotSwapClassLoader  extends  URLClassLoader {  
  19.    
  20.     public  HotSwapClassLoader(URL[] urls) {  
  21.         super  (urls);  
  22.     }  
  23.    
  24.     public  HotSwapClassLoader(URL[] urls, ClassLoader parent) {  
  25.         super  (urls, parent);  
  26.     }  
  27.    
  28.     public  Class load(String name)  
  29.           throws  ClassNotFoundException {  
  30.         return  load(name,  false  );  
  31.     }  
  32.    
  33.     public  Class load(String name,  boolean  resolve)  
  34.           throws  ClassNotFoundException {  
  35.         if  (  null  !=  super  .findLoadedClass(name))  
  36.             return  reload(name, resolve);  
  37.    
  38.         Class clazz = super  .findClass(name);  
  39.    
  40.         if  (resolve)  
  41.             super  .resolveClass(clazz);  
  42.    
  43.         return  clazz;  
  44.     }  
  45.    
  46.     public  Class reload(String name,  boolean  resolve)  
  47.           throws  ClassNotFoundException {  
  48.         return   new  HotSwapClassLoader(  super  .getURLs(),  super  .getParent()).load(  
  49.             name, resolve);  
  50.     }  
  51. }  
  52.    
  53. public   class  A {  
  54.     private  B b;  
  55.    
  56.     public   void  setB(B b) {  
  57.          this  .b = b;  
  58.     }  
  59.    
  60.     public  B getB() {  
  61.          return  b;  
  62.     }  
  63. }  
  64.    
  65. public   class  B {}  

 

 

这个类的作用是可以重新载入同名的类, 但是, 为了实现hotswap, 老的对象状态
需要通过其他方式拷贝到重载过的类生成的全新实例中来。(A类中的b实例)

而新实例所依赖的B类如果与老对象不是同一个类加载器加载的, 将会抛出类型转换异常(ClassCastException).

为了解决这种问题, HotSwapClassLoader自定义了load方法. 即当前类是由自身classLoader加载的, 而内部依赖的类

 

还是老对象的classLoader加载的.

 
Java代码  收藏代码
  1. public   class  TestHotSwap {  
  2. public   static   void  main(String args[]) {  
  3.     A a = new  A();  
  4.     B b = new  B();  
  5.     a.setB(b);  
  6.    
  7.     System.out.printf("A classLoader is %s n"  , a.getClass().getClassLoader());  
  8.     System.out.printf("B classLoader is %s n"  , b.getClass().getClassLoader());  
  9.     System.out.printf("A.b classLoader is %s n"  ,   a.getB().getClass().getClassLoader());  
  10.    
  11.     HotSwapClassLoader c1 = new  HotSwapClassLoader(  new  URL[]{  new  URL(  "file:\e:\test\" )} , a.getClass().getClassLoader());  
  12.     Class clazz = c1.load(" test.hotswap.A " );  
  13.     Object aInstance = clazz.newInstance();  
  14.    
  15.     Method method1 = clazz.getMethod(" setB " , B. class );  
  16.     method1.invoke(aInstance, b);  
  17.    
  18.     Method method2 = clazz.getMethod(" getB " null );  
  19.     Object bInstance = method2.invoke(aInstance, null );  
  20.    
  21.     System.out.printf(" reloaded A.b classLoader is %s n" , bInstance.getClass().getClassLoader());  
  22. }  
  23. }  
 

 

输出

A classLoader is sun.misc.Launcher$AppClassLoader@19821f
B classLoader is sun.misc.Launcher$AppClassLoader@19821f
A.b classLoader is sun.misc.Launcher$AppClassLoader@19821f
reloaded A.b classLoader is sun.misc.Launcher$AppClassLoader@19821f

分享到:
评论

相关推荐

    classloader

    3. 整合自定义ClassLoader:了解如何将自定义的ClassLoader集成到Java应用程序中,替换或扩展默认的加载行为。 4. 考虑Java 2版本的兼容性:学习如何修改你的ClassLoader以适应Java 2及以上版本的特性,比如支持...

    ClassLoader

    在这个阶段,`ClassLoader`负责完成以下三项基本工作: 1. **通过一个类的全限定名来获取该类的二进制字节流**。 2. **将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构**。 3. **在Java堆中生成一个...

    ClassLoader运行机制 自己写的

    3. System ClassLoader(也称为AppClassLoader):加载`CLASSPATH`环境变量指定的类,以及应用主类路径(class path)上的类。 4. WebLogic特定的ClassLoaders: - Ear ClassLoader:加载EAR应用的全局库(如lib...

    自定义classloader的使用

    三、自定义加载路径 默认情况下,Classloader从JAR文件或当前目录(CLASSPATH)加载类。通过自定义Classloader,我们可以指定额外的类路径,例如从网络、数据库或者本地文件系统的非标准位置加载类。这在处理动态...

    Java ClassLoader定制实例

    3. 性能:频繁的类加载会影响性能,因此应尽量减少不必要的类加载操作。 在实际应用中,我们可以通过反射API来使用自定义ClassLoader加载的类。例如,我们可以创建一个`Class`对象,然后调用`newInstance()`方法来...

    ClassLoader小例子

    3. **ClassLoader的工作流程** - 加载:查找并加载类的二进制数据。 - 验证:确保加载的类数据符合JVM规范,不会危害系统安全。 - 准备:为类的静态变量分配内存并初始化它们的默认值。 - 解析:将符号引用转化...

    java ClassLoader机制及其在OSGi中的应用

    3. OSGi的ClassLoader还支持类的重用,如果两个bundle引用了相同的类库,它们可以共享同一个ClassLoader,从而节省内存资源。 总结来说,Java ClassLoader机制是Java平台的基础,它使得程序能够动态地加载和管理类...

    深入理解ClassLoader工作机制.docx

    3. **准备**:在准备阶段,JVM为类的静态变量分配内存,并将其初始化为默认值(例如,int为0,引用类型为null)。 4. **解析**:解析涉及将符号引用转换为直接引用,使得JVM能够找到类、方法和字段的实际位置。 5....

    JVM ClassLoader简析

    首先,ClassLoader可以分为三种基本类型:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。Bootstrap ClassLoader是JVM启动时的第一个ClassLoader,负责加载JDK的`<JAVA_HOME>\lib`目录下...

    理解Java ClassLoader机制

    3. **链接**:链接阶段包括三个子步骤:验证、准备和解析。验证确保字节码符合JVM规范;准备阶段为类的静态变量分配内存并初始化它们的默认值;解析阶段将符号引用转换为直接引用。 4. **初始化**:如果类还没有被...

    ClassLoader 详解.doc

    3. System ClassLoader:系统类加载器,也称为应用程序类加载器。它负责加载应用的主类路径(classpath)中的类,即通过-classpath或-Djava.class.path系统属性指定的路径。System ClassLoader的父加载器是Extension...

    ClassLoader 案例

    Java中的类加载过程分为三个阶段:加载、验证、准备、解析和初始化。默认情况下,系统使用Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader来加载不同路径下的类。自定义ClassLoader则允许我们插入这...

    ClassLoader的 一些测试

    ClassLoader有三种类型: 1. Bootstrap ClassLoader:这是最基础的类加载器,由C++实现,负责加载JDK核心库(rt.jar)。 2. Extension ClassLoader:扩展类加载器,负责加载JRE的扩展目录(jre/lib/ext目录下的jar...

    java classloader

    ClassLoader分为三个主要层次:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader(也称为System ClassLoader)。Bootstrap ClassLoader是JVM启动时的第一个ClassLoader,负责加载JRE的`<JAVA_HOME>/...

    ClassLoader类加载机制和原理详解

    3. 自定义ClassLoader 开发者可以通过继承java.lang.ClassLoader类,创建自己的类加载器。这在处理动态加载、插件系统、隔离应用域等场景时非常有用。自定义类加载器需要覆盖`findClass()`方法,实现类的查找和加载...

    ClassLoader原理

    3. 第三行表示系统类加载器父类加载器的父类加载器为`Bootstrap ClassLoader`。 4. 第四行表示核心类`java.lang.Object`是由`Bootstrap ClassLoader`加载的。 5. 第五行表示用户类`LoaderSample1`是由系统类加载器...

    深入了解Java_ClassLoader,Bytecde.pdf

    #### 三、Java 2中ClassLoader的变化 **3.1 loadClass() 的默认实现** 在Java 2中,`loadClass()` 方法的实现变得更加通用化,可以通过覆盖 `findClass()` 方法来自定义类的查找逻辑。这减少了自定义 `ClassLoader...

Global site tag (gtag.js) - Google Analytics