首页  

JVM类加载器     所属分类 jvm 浏览量 842
对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,
每一个类加载器,都拥有一个独立的类名称空间。


比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,
否则,即使这两个类来源于同一个Class文件,被同一个Java虚拟机加载,
只要加载它们的类加载器不同,那这两个类就必定不相等。


这里所指的“相等”,包括代表类的Class对象的equals()方法、
isAssignableFrom()方法、isInstance()方法的返回结果,
也包括了使用instanceof关键字做对象所属关系判定等各种情况

从java虚拟机角度看有俩种不同的类加载器

启动类加载器(Bootstrap ClassLoader)   C++实现
所有其他的类加载器(全部都继承自抽象类java.lang.ClassLoader)          java实现

从开发人员角度看

启动类加载器Bootstrap ClassLoader
负责将存放在 JAVA_HOME\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,
并且是虚拟机识别的类库加载到虚拟机中
仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载
启动类加载器无法被java程序直接引用,用户在编写自定义类加载时,
如果需要把加载请求委派给引导类加载器,直接使用null即可

扩展类加载器Extension ClassLoader

这个加载器由sun.misc.Launcher$ExtClassLoader实现
负责加载JAVA_HOME\lib\ext目录中的,或者 java.ext.dirs系统变量所指定的路径的所有类库
开发者可以直接使用扩展类加载器

应用程序加载器Application ClassLoader
sun.misc.Launcher$AppClassLoader
ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。
负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器。
如果应用程序中没有自定义自己的类加载器,一般情况下这个就是程序中默认的类加载器。

双亲委派模型
双亲委派模型的工作流程

 当类加载器接收到类加载的请求时,它不会自己去尝试加载这个类,
 而是把这个请求委派给父加载器去完成,每一个层次的类加载器都是如此,
 因此所有的请求最终都应该传送到启动类加载器中,
 只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围内没有找到所需的类)时,
 子加载器才会尝试自己去加载。


优点:java类随着它的类加载器一起具备了一种带有优先级的层次关系。
    
java.lang.Object 在rt.jar中


双亲委派模型的实现


protected synchronized Class< ?> loadClass(String name, Boolean resolve) throws ClassNotFoundException{
    //首先检查请求的类是否已经被加载过
    Class c = findLoadedClass(name);
         if(c == null){
         try{
             if(parent != null){
             //委派父类加载器加载
             c = parent.loadClass(name, false);
         }
         else{
              //委派启动类加载器加载
             c = findBootstrapClassOrNull(name);
         }
         }catch(ClassNotFoundException e){
             //父类加载器无法完成类加载请求
         }
         if(c == null){
              //本身类加载器进行类加载
             c = findClass(name);
         }
     }
     if(resolve){
         resolveClass(c);
     }
     return c;
}


双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。
不过这里类加载器之间的父子关系一般不是以继承(Inheritance)的关系来实现的,
而是通常使用组合(Composition)关系来复用父加载器的代码。

双亲委派模型的破坏
JDK1.2才有双亲委派模型,面对已经存在的用户自定义类加载器的代码,
为了兼容这些已有代码,无法再以技术手段避免loadClass()被子类覆盖的可能性,
只能在JDK 1.2之后的java.lang.ClassLoader中添加一个新的protected方法findClass(),
并引导用户编写的类加载逻辑时尽可能去重写这个方法,而不是在loadClass()中编写代码。

由这个模型自身的缺陷导致的,如果有基础类型又要调用回用户的代码。

由于用户对程序动态性的追求而导致的,这里所说的“动态性”指的是一些非常“热”门的名词
代码热替换(Hot Swap)、模块热部署(HotDeployment)等

OSGi实现模块化热部署的关键是它自定义的类加载器机制的实现,
每一个程序模块(OSGi中称为Bundle)都有一个自己的类加载器,
当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。
在OSGi环境下,类加载器不再双亲委派模型推荐的树状结构,而是进一步发展为更加复杂的网状结构

上一篇     下一篇
java class类文件结构

JVM字节码指令

JVM类加载过程

修佛必读《心经》《金刚经》《楞严经》

JVM模块化系统

Mac快速锁屏