`

一步一步深入jvm(4)—jvm classloader体系结构及加载原理

    博客分类:
  • jvm
阅读更多

      我们正常遇到这样的情况,自定义一个jar文件中包含一个class【类】文件。我们想重写这个类的话直接在工程中包名及类名一致就可行。
      但是对于某些类文件例如String等一些类,在我们的工程中直接重写这些类,是调用不了的。这是什么原因呢?
      这和java的类的加载机制有关,那到底java是怎么加载类文件?这个问题也是下文将阐述的问题。

      首选要提到的是ClassLoader,那什么是ClassLoader?
      ClassLoader负责将相应的类文件(即class文件)装载到内存中。jvm中存在多种类型的ClassLoader,主要分为4类:
     (1)BootStrap[启动类加载器] 是最顶层的类加载器,它是由C++编写而成,并且已经内嵌到JVM中了,主要用来读取Java的核心类库JRE/lib/rt.jarresources.jar、charsets.jar
    (2)Extension ClassLoader[扩展类加载器] 是用来读取Java的扩展类库,读取JRE/lib/ext/*.jar
    (3)App ClassLoader[应用类加载器] 是用来读取当前应用下CLASSPATH指定的所有jar包或目录的类文件【是用户自定义类装载器的缺省父装载器】。
    (4)Custom ClassLoader[用户自定义类加载器] 是用户自定义编写的,它用来读取指定类文件

    不同的类装载器,只能加载相应范围的类,哪怕是同包下的类,只要他们不属于同一类装载器,都是相互隔绝的。这对一些有安全隐患的类起到了安全隔离的作用。使它不能冒充系统类来破坏程序正常运作。

    这些ClassLoader组成了jvm的ClassLoader的体系结构,如下图所示为。

   classLoader体系结构

   从图中我们可以看出,当加载一个类的时候,是先检查是当前加载器是否已经加载该类,如已加载则返回。否则委托给它的父加载器检查是否已经加载,一直检查到BootStrap【启动类加载器】,如果还是没有发现该类被加载,则BootStrap【启动类加载器】尝试加载该类,加载成功则返回,如没有加载到则将委托还给子装载器,子类加载器继续加载,一直装载到最底层的ClassLoader【可能为App ClassLoader或者Custom ClassLoader,甚至可能为Extension ClassLoader】,如果没有装载到相应的类则抛出ClassNotFoundException。整个模型也称作双亲委派模型。

   总结来说 双亲委派方式的类加载,指的是优先从顶层启动类加载器开始,自顶向下的方式加载类的模型 (参见图示)。 

   可能有点迷糊,我们结合一个实际的源码来说明该模型。

   java中的Launcher类【在sun.misc包下】,它包含两个内部类AppClassLoader、ExtClassLoader,java通过这两个类完成对应用及扩展类文件的加载,它们继承URLClassLoader类,而URLClassLoader类继SecureClassLoader类,SecureClassLoader继承抽象类ClassLoader。
   它们的类图关系如下

 

     虽然AppClassLoader、ExtClassLoader都是继承于URLClassLoader,但是AppClassLoader的父加载器为ExtClassLoader【这里就不多讲了,可以看看源码就知道了】。而对于AppClassLoader、ExtClassLoader类中并未覆盖抽象类ClassLoader的loadClass方法。ClassLoader的loadClass的方法如下

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 {
         //如果父加载器不存在调用BootStrap查看是否已被加载
      c = findBootstrapClass0(name);
  }
     } catch (ClassNotFoundException e) {
         // If still not found, then invoke findClass in order
         // to find the class.
                //如果顶级装载器BootStrap未发现已加载该类,增尝试加载该类
         c = findClass(name);
     }
 }
 if (resolve) {
     resolveClass(c);
 }
 return c;
    }

    而findBootstrapClass0方法如下

 

    private Class findBootstrapClass0(String name)
	throws ClassNotFoundException
    {
	check();
	if (!checkName(name))
	    throw new ClassNotFoundException(name);
	return findBootstrapClass(name);
    }

    private native Class findBootstrapClass(String name)
	throws ClassNotFoundException;

     它是一个本地接口的方法时C++写的。

     从源码中可以看出ClassLoader总是现从下往上查看类是否已被加载,然后从上往下尝试加载类。

    一般自定类加载器时loadClass是不重写,而自定义加载器重写的是findClass。从源码中我们可以看出,所有加载器的顶级加载器为BootStrap【即父加载器不存时】,同时注意到的时出于安全等因素考虑, BootStrap不会加载 lib 存在的陌生类或jar 开发者通过将要加载的非 JDK 自身的类放置到此目录下期待启动类加载器加载是不可能的,其他类加载器无这样的限制
   示例代码如下

public class classLoaderTest {
 public static void main( String args[]  ){
   classLoaderTest t = new classLoaderTest();
   System.out.print( t.getClass() );
   System.out.println( t.getClass().getClassLoader() ) ; 
   System.out.println( t.getClass().getClassLoader().getParent() ) ; 
   System.out.println( t.getClass().getClassLoader().getParent().getParent() ) ;    
  }
}

 

类加载器查看如下

class classLoaderTest
sun.misc.Launcher$AppClassLoader@82ba41
sun.misc.Launcher$ExtClassLoader@923e30
null

 

      第二行的结果表示 classLoaderTest 的类的加载器为 AppClassLoader

       第三行的结果表示  AppClassLoader的父加载器为 ExtClassLoader

       第四行的结果null表示  ExtClassLoader 的父加载器为 BootStrap

       整个的加载流程如下自定类classLoaderTest,创建该类对象时,先是AppClassLoader检查是否已经加载该类,AppClassLoader并未加载该类,AppClassLoader委托给ExtClassLoader,而ExtClassLoader也未发现已经装载该类ExtClassLoader将委托交给BootStrap,BootStrap也未发现。这时BootStrap将尝试加载classLoaderTest,BootStrap未加载到,将委托交还给ExtClassLoader,ExtClassLoader未加载到,将委托交还给AppClassLoader,AppClassLoader加载到该类,并创建classLoaderTest。

      这里我们回到问题为什么对于String等类,在应用重写,为什么不能覆盖系统的String类型。

     从双亲委派模型 中我们可以知道,String对象存在rt.jar中它是由BootStrap负责加载,这样我们在应用中重写该类的时候无法加载自定义的String类【且是永远加载不到】,只能加载系统的String,这里也是java沙箱模型的第一保障。

 

   备注:

java –verbose:class ClassLoaderTest


可以查看具体的类运行的时候类加载过程

 图及部分类容参考

  http://www.cnblogs.com/ChrisWang/archive/2009/11/17/Inside-JVM-4-ClassLoader-Knowledge-Sharing.html

  • 大小: 313.8 KB
  • 大小: 16.4 KB
0
0
分享到:
评论

相关推荐

    classloader体系结构(含hotswap)

    Java的类加载器(ClassLoader)体系结构是JVM(Java虚拟机)中至关重要的一部分,它负责将类的字节码转换为运行时的类实例。本文将深入探讨启动类加载器、扩展类加载器、系统类加载器以及用户自定义类加载器,同时还...

    jvm的基本原理及结构

    2. **类加载机制**:JVM使用类加载器(ClassLoader)将.class文件加载到内存中,类加载器体系结构包括Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader,它们分别负责加载不同的类库。...

    jvm 加载class文件

    Java类加载器体系结构主要包括以下几种类型的加载器: 1. **启动类加载器(Bootstrap ClassLoader)**:负责加载Java的核心类库(位于JRE/lib/rt.jar等文件中),这是系统级别加载器,无法通过Java代码直接获取。 2...

    JVM原理讲解和调优,详细讲解JVM底层

    字节码的执行则依赖于JVM执行引擎,它通过基于栈的体系结构来执行字节码指令。每个线程都会有一个程序计数器和栈来跟踪方法调用,栈中存放了栈帧,其中包含了局部变量区和操作数栈。 在Java平台中,JDK(Java ...

    jvm原理及调优

    ### JVM原理及调优 #### 一、JVM概述 JVM(Java Virtual Machine,Java虚拟机)是Java编程语言的基础,它作为一种软件层面的抽象计算机,能够在多种操作系统平台上执行Java字节码程序。Java编译器的目标是生成能够...

    深入JVM整理文档

    2. **加载**:使用类加载器(ClassLoader)加载字节码到JVM。 3. **执行**:JVM解释执行字节码,可能还会涉及即时编译(JIT)以提高性能。 #### 1.3、加载.class文件的方式 Java程序可以通过以下几种方式加载....

    JVM体系结构与GC调优

    **JVM体系结构与GC调优** Java虚拟机(JVM)是Java应用程序的核心组成部分,它为Java程序提供了跨平台的运行环境。了解JVM的体系结构和垃圾收集(Garbage Collection, GC)机制对于优化Java应用性能至关重要。 **1...

    JAVA ClassLoader 讲解 (类加载器)

    Java的类加载器体系结构由三个主要类型的类加载器组成: 1. **引导类加载器(Bootstrap ClassLoader)**:这是最基础的类加载器,负责加载Java的核心库类,如`java.lang`包下的类。 2. **扩展类加载器(Extension ...

    ClassLoader

    在Java编程语言中,`ClassLoader`是一个非常重要的组件,它负责加载程序运行所需的类文件到Java虚拟机(JVM)中。`ClassLoader`不仅管理着类的加载过程,而且其设计模式还对Java的安全性和性能有着至关重要的影响。 #...

    JVM原理.docx

    ### JVM原理核心知识点详解 ...综上所述,Java虚拟机的原理不仅涉及其生命周期和体系结构的基本概念,还包括类加载过程以及内存管理和垃圾回收等关键方面。了解这些原理对于深入理解Java程序的运行机制至关重要。

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

    二、ClassLoader的体系结构 ClassLoader形成一个树状结构,BootstrapClassLoader是根节点,ExtensionClassLoader是其子节点,SystemClassLoader是ExtensionClassLoader的子节点。用户还可以自定义ClassLoader,插入...

    JVM-整体结构原理深度解析

    #### 二、JVM体系结构概览 JVM启动后,在操作系统层面表现为一个独立的进程,其内部架构包括以下几个关键组成部分: ##### 2.1 类装载器(ClassLoader) 类装载器负责加载Java类文件(.class文件)。这些文件包含...

    JVM笔记.docx

    【JVM 体系结构概述】 Java 虚拟机(JVM)是Java应用程序的核心,它作为操作系统上的一个抽象层,使得Java代码可以在任何支持JVM的平台上运行,无需关心底层系统的具体细节。JVM主要由以下几个部分构成: 1. 类...

    Tomcat研究之ClassLoader.pdf

    #### 二、Tomcat的ClassLoader体系结构 Tomcat采用了独特的类加载机制来处理不同的类库加载需求。其ClassLoader体系结构可以分为以下几个层次: 1. **Bootstrap ClassLoader**:这是JVM自带的类加载器,负责加载...

    jvm基础学习,介绍各种jvm里面的知识点,和深入理解java虚拟机很像,易懂

    类加载过程中采用的双亲委派模型是一种层次结构的类加载器体系结构,它的工作方式如下: 1. 当一个类加载器收到加载类的请求时,它首先尝试让其父类加载器加载该类;如果父类加载器不存在或无法加载,则自行尝试...

    JVM详解-淘宝内部资料

    "JVM详解-淘宝内部资料"提供了一套深入理解JVM的资源,涵盖了从基础到高级的各种主题,包括Java虚拟机的生命周期、JVM的体系结构、各个组件的详细解析以及垃圾收集(Garbage Collection, GC)机制等内容。...

    JVM的那些事.pptx

    - **基于栈的体系结构**:JVM是基于栈的体系结构,通过操作数栈来执行字节码指令。 - **栈帧**:代表了一个方法的一次调用,包含局部变量区和操作数栈。局部变量区用于存储局部变量和方法参数;操作数栈用于存放...

    JVM的学习.pdf

    JVM的体系结构包括几个重要组成部分:类装载器(ClassLoader)、执行引擎(ExecutionEngine)、本地方法栈(Native Method Stack)、PC(程序计数器)寄存器等。其中,类装载器负责将.class文件加载进内存,执行引擎...

Global site tag (gtag.js) - Google Analytics