`
greemranqq
  • 浏览: 966440 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

JVM 类加载器介绍

    博客分类:
  • JVM
阅读更多

 通过一个类的全限定名来获取描述此类的二进制字节流,这个动作放到虚拟机外部去实现,以便让程序自己决定如何去获取所需要的类。这个模块的动作成为“类加载器”。
        唯一性:对于任意一个类,必须类的加载器和类本身,同时来确立其唯一性,每一个类加载器,都拥有一个独立的类的名称空间。
 比较两个类是否相等,只有在两个类是由同一个类加载器加载的前提下才有意义,否则即使两个类来源于同一个class 文件,被同一个虚拟机加载,只要加载器不同,那么他们两个类必定不同。这里的“相等”包括对象的equals(),isAssignableForm(),isInstance 方法的返回结果。可以代码简单演示:

public class ClassLoaderTest {
 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
 ClassLoader myLoder = new ClassLoader() {
  @Override
  public Class<?> loadClass(String name) throws ClassNotFoundException {
  String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
  InputStream in = getClass().getResourceAsStream(fileName);
    Class<?> c = null;
    try {
     if(in == null){
      return super.loadClass(name);
     }
     byte[] b = new byte[in.available()];
     in.read(b);
     c = defineClass(name, b, 0, b.length);
    } catch (Exception e) {
     e.printStackTrace();
    }
    return c;
   }
  };
  Object obj = myLoder.loadClass("com.ClassLoaderTest").newInstance();
  System.out.println(obj.getClass());
  System.out.println(obj instanceof com.ClassLoaderTest);
 }
}

 结果:
class com.ClassLoaderTest
false

返回false 是因为系统存在两个ClassLoaderTest,一个是系统默认加载的,一个是自己new 的加载器,虽然是用一个class 文件,但是依然是独立的两个类。而我们经常做equals判断的时候会先进行instanceof 检查,大多数情况都是true,因为统一是默认的加载器加载的,下面看看一些加载器的工作情况。

一、双亲委派模型
 从JAVA虚拟机的角度来说,主要有两个加载器:一种是启动了加载器
(Bootstrap ClassLoader),这是由C++写的,是虚拟机一部分,另一种是其他类的加载器,是有Java实现的,独立于虚拟机外,并且都继承自抽象类java.lang.ClassLoader.细分一下,可以分为扩展类加载器(Extension ClassLoader)和应用程序加载器(Application ClassLoader)。

        1.启动类加载器:主要负责加载<JAVA_HOME>\lib 目录中的,虚拟机能识别的文件名的文件。这个加载器无法没Java程序直接用。
 2.扩展类加载器:主要负责加载<JAVA_HOME>\lib\ext下的,或者被java.ext.dirs 系统变量指定的类库,开发者可以直接使用的。
 3.应用类加载器:主要负责加载用户类路径(classpath)上所指定的类库,程序中默认的类加载器,开发者可以自己进行使用。
 这几个加载器在rt.jar sun.misc.Launcher 下,这里我还进不去..!他们直接由上到下的关系,就是双亲委派模型,关于这个模型定义,这里大概介绍一下,它要求除了启动类加载器以外,其他都需要自己的父类加载器,并且父子关系不是继承,而是组合,也就是说类的加载会先让最上面的进行加载,加载不了的,再让后面的进行加载,你会发现每次都会从启动类加载器开始,而且object 这个最大的父类就在rt.jar 里面,也是有启动类加载器进行加载的。这种模式是JDK推荐的,因为如果不按这种方式,自己写个Object 类,自己定义的位置进行加载,那么会混乱。
 对于双亲委派模型代码都集中在java.lang.ClassLoader 的loadClass 中,可以通过图和源码进行了解:
图参考:http://yueyemaitian.blog.163.com/blog/static/2165043320097211052534/

 

  

protected synchronized Class<?> loadClass(String name, boolean resolve)
 throws ClassNotFoundException
    {
 //1.  先检查是否被加载过了
 Class c = findLoadedClass(name);
 if (c == null) {
     try {
  if (parent != null) {
      c = parent.loadClass(name, false);
  } else {
      c = findBootstrapClass0(name);
  }
     } catch (ClassNotFoundException e) {
         // 2. 如果父类找不到,就抛出ClassNotFoundException
  // 默认直接抛出异常,JDK要求重写这个方法
         c = findClass(name);
     }
 }
 if (resolve) {
     resolveClass(c);
 }
 return c;
    }  

  

注:JDK 建议我们在实现自己的加载器的时候,不要覆盖locaClass方法,而是建议我们去重写findClass 方法,这样能保证双亲委派模型,同时也实现了自己的方法。

           双亲委派模型比较稳定,能很好的解决类加载的基础类问题(越基础的类,越由上层加载器进行记载),这些了之所以叫"基础",因为他们总是被用户代码调用API,但是在某些时候,这些基础类又要会调回用户代码,怎么办呢?
           比如:用户调用基础类的method-1 方法,而该方法又要调用用户自己写的method-2,这类引用场景一般会在API写了接口,或者一种实现方法,而我们调的时候需要实现自己的方法,比如JDBC,JDNI,提供了接口,具体的实现需要各个不同的数据库厂商去实现,这里就是不基本的双亲委派模型了。
           JNDI现在放在rt.jar 里面,目的是对资源进行查找和集中管理,他需要独立厂商去实现并部署,而启动类加载器不识别这些代码,怎么办呢?
           Java 团队又设计了一个上下文类加载器(Thread Context ClassLoader),可以通过java.lang.Thread 的setContextClassLoder 进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果程序全局都没设置过,那么默认还是App应用程序加载器。
           有了线程上下文加载器,就能加载厂商独立实现的代码了,也就是父类加载器请求子类加载器去完成类的加载动作,双亲委派模型是父类先加载,加载不了再给子类加载,而这里是父类直接请求子类加载,已经破坏了委派模型层次。其中JCE、JAXB、JBI都也都采用了。

           其次,用户在追求程序动态性的时候,希望程序想USB 接口一样,可以不用重启电脑,而更换各种外接东西。为了完成这个诱人的操作,比如OSGI实现了模块化热部署,它的关键是自己定义类加载器的实现机制,每一个模块都有自己的类加载器,需要更换模块的时候,就把模块和类加载器一起换掉,实现热替换。(ps:这玩意儿我也没用过,感觉就像webservice 远程调用那样,规定了接口,客户端固定,然后可以随意的替换服务端,从而客户端获得不同的输出)

           关于osgi 的原理以及机制,可以参考<深入理解osgi>..之类的书。

小结:
 1.这里主要介绍了类加载器的种类以及运行原理,方便我们加深对类的理解
 2.这些都参考JVM里面的东西,写成小章节,方便自己理解,也分享一部分经验。

 

 

 

分享到:
评论

相关推荐

    JVM类加载器 test

    JVM类加载器 test

    深入Java虚拟机_002_深入详解JVM之类加载器深度剖析、根、扩展及系统类加载器

    深入Java虚拟机_002_深入详解JVM之类加载器深度剖析、根、扩展及系统类加载器

    JVM类加载跟踪器

    JVM类加载跟踪器,用于排查jar包冲突、类冲突、类版本冲突、NoClassDefFoundError、ClassNotFoundException 等等类加载相关问题的辅助工具

    JVM类加载器说明文档

    介绍Java类的加载机制,对于深入理解Java的深层原理很有帮助

    Java虚拟机JVM类加载初始化

    由Java虚拟机自带的默认加载器(根加载器、扩展加载器、系统加载器)所加载的类在JVM生命周期中始终不被卸载。所以这些类的Class对象(我称其为实例的模板对象)始终能被触及!而由用户自定义的类加载器所加载的类会...

    【JVM】类加载器与双亲委派模型

    内嵌在JVM内核中的加载器,由C++语言编写(因此也不会继承ClassLoader),是类加载器层次中最顶层的加载器。用于加载java的核心类库,即加载jre/lib/rt.jar里所有的class。由于启动类加载器涉及到虚拟机本

    JVM核心机制_深入类加载器_层次结构(三种类加载器)_代理加载模式_双亲委派机制_类加载器

    JVM核心机制_深入类加载器_层次结构(三种类加载器)_代理加载模式_双亲委派机制

    类加载器(java)

    当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构,理解类加载器:J2EE 环境下的 log4j.files

    jvm类加载器基础解析

    主要介绍了jvm类加载器基础解析,具有一定借鉴价值,需要的朋友可以参考下

    JAVA-JVM-01类加载机制

    java中JVM类加载器和双亲委派机制剖析,类加载示例、加载器示例、自定义一个类加载器示例;Tomcat自定义加载器详解

    wanglijun93#AndroidNote#JVM类加载器1

    第一阶段要验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理 第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言

    JVM:类加载器子系统.pdf

    总结了类加载器子系统相关的内容,主要包括类加载器子系统的作用、ClassLoader角色、加载的过程、双亲委派机制以及沙箱安全机制等内容

    JVM、Tomcat、OSGI等类加载器整理文档

    这里将JVM、OSGI、Tomcat以及OSGI和Web服务器整合平台的类加载器做了详细的说明和分析,能让你对类加载器的做一个较为系统的了解。

    掌握Java类加载器

    类加载器从源文件(通常是.class 或 .jar文件)获得不依赖平台的字节码,然后将它们加载到JVM内存空间,所以它们能被解释和执行。默认状态下,应用程序的每个类由java.lang.ClassLoader加载。因为它可以被继承,所以...

    Java面试题-内存+GC+类加载器+JVM调优.pdf

    Java面试题-内存+GC+类加载器+JVM调优

    JVM(三):类加载机制(类加载过程和类加载器)1

    1.编写个向接的应程序,可能等到运时再指定其实现的类 2.户可以定义个类加载器,让程序在运时从络或其他地加载 1.加载:(重点) 1.通过“类全名”来获取定义此

    轻松搞定jvm类加载器

    而**当我们需要用到某个类时,jvm将会加载它,并在内存中创建对应的class对象,这个过程称之为类的加载。**过程如下: 类的加载、连接、初始化 1. 加载 通过类的包名和雷鸣查找到此类的字节码文件,将xx.class文件...

    java类加载机制.xmind

    该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...

    JVM的类加载过程以及双亲委派模型详解

    主要介绍了JVM的类加载过程以及双亲委派模型详解,类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象。,需要的朋友可以参考下

Global site tag (gtag.js) - Google Analytics