热点推荐:Java类加载器深入理解

开发 后端
本篇文章主要是详细写一下个人对Java ClassLoader的理解。

首先回顾一下,java虚拟机载入java类的步骤:java文件经过编译器编译后变成字节码文件(.class文件),类加载器 (ClassLoader)读取.class文件,并且转换成java.lang.Class的一个实例,***通过newInstance方法创建该类的 一个对象。ClassLoader的作用就是根据一个类名,找到对应的字节码,根据这些字节码定义出对应的类,该类就是java.lang.Class的 一个实例。

类加载器的组织结构

java有三个初始类加载器,当java虚拟机启动时,它们会按照以下顺序启动:Bootstrap classloader -> extension classloader -> system classloader。三者的关系:bootstrap classloader是extension classloader的parent,extension classloader是system classloader的parent。

bootstrap classloader

它是最原始的类加载器,并不是由java代码写的,是由原生代码编写的。Java有一次编译、所有平台运行的效果,就是因为它写了一份功能相同,但针对不同平台不同语言实现的底层代码。它负责加载java核心库,大家可运行以下代码,看看自己本地的java核心库在哪里:

  1. URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs(); 
  2. for (int i = 0; i < urls.length; i++) { 
  3. System.out.println(urls[i].toExternalForm()); 

本人的运行结果:

  1. file:/home/eric/jdk1.6.0_35/jre/lib/resources.jar 
  2. file:/home/eric/jdk1.6.0_35/jre/lib/rt.jar 
  3. file:/home/eric/jdk1.6.0_35/jre/lib/sunrsasign.jar 
  4. file:/home/eric/jdk1.6.0_35/jre/lib/jsse.jar 
  5. file:/home/eric/jdk1.6.0_35/jre/lib/jce.jar 
  6. file:/home/eric/jdk1.6.0_35/jre/lib/charsets.jar 
  7. file:/home/eric/jdk1.6.0_35/jre/lib/modules/jdk.boot.jar 
  8. file:/home/eric/jdk1.6.0_35/jre/classes 

extension classloader

它用来加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或java.ext.dirs系统属性指定的)JAR的类包。注意,因为它是bootstrap classloader加载的,所以当你运行:

ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());

输出的是:the parent of extension classloader : null

system classloader

它用于加载classpath目录下的jar包,我们写的java类,一般都是由它加载,除非你自己制定个人的类加载器。

全盘负责委托机制

classloader加载类时,使用全盘负责委托机制,可以分开两部分理解:全盘负责,委托。

全盘负责机制:若类A调用了类B,则类B和类B所引入的所有jar包,都由类A的类加载器统一加载。

委托机制:类加载器在加载类A时,会优先让父加载器加载,当父加载器加载不到,再找父父加载器,一直找到bootstrap  classloader都找不到,才自己去相关的路径去寻找加载。以下是ClassLoader的源码:

  1. protected synchronized Class<?> loadClass(String name, boolean resolve) 
  2. throws ClassNotFoundException 
  3.     { 
  4. // First, check if the class has already been loaded 
  5. Class c = findLoadedClass(name); 
  6. if (c == null) { 
  7.     try { 
  8.   if (parent != null) { 
  9.       //从父加载器加载 
  10.       c = parent.loadClass(name, false); 
  11.   } else { 
  12.       //从bootstrap loader加载 
  13.       c = findBootstrapClassOrNull(name); 
  14.   } 
  15.     } catch (ClassNotFoundException e) { 
  16.                 // ClassNotFoundException thrown if class not found 
  17.                 // from the non-null parent class loader 
  18.             } 
  19.             if (c == null) { 
  20.         // If still not found, then invoke findClass in order 
  21.         // to find the class. 
  22.         c = findClass(name); 
  23.     } 
  24. if (resolve) { 
  25.     resolveClass(c); 
  26. return c; 
  27.     } 

举个例子,类加载器加载类A的过程:

1,判断是否已经加载过,在cache里面查找,若有,跳7;否则下一步

2,判断当前加载器是否有父加载器,若无,则当前为ext classloader,跳去4;否则下一步

3,请求父加载器加载该类,若加载成功,跳7;若不成功,即父加载器不能找到该类,跳2

4,请求jvm的bootstrap classloader加载,若加载成功,跳7;若失败,跳5

5,当前加载器自己加载,若成功,跳7;否则,跳6

6,抛出ClassNotFoundException

7,返回Class

编写自己的类加载器

Java加载类的过程,实质上是调用loadClass()方法,loadClass中调用findLoadedClass()方法来检查该类是否 已经被加载过,如果没有就会调用父加载器的loadClass(),如果父加载器无法加载该类,就调用findClass()来查找该类。

所以我们要做的就是新建MyClassLoader继承java.lang.ClassLoader,重写其中的findClass()方法。主要是重新设计查找字节码文件的方案,然后调用definedClass来返回。

本人写了一个demo,用自己的类加载器去加载指定java文件,且带有热部署效果,具体请查看以下url。

Demo地址:http://git.oschina.net/ericquan8/hot-deploy

 

责任编辑:王雪燕 来源: ericquan8
相关推荐

2021-09-24 08:10:40

Java 语言 Java 基础

2011-02-25 09:23:00

Java类加载器

2022-10-12 07:53:46

并发编程同步工具

2016-12-08 15:36:59

HashMap数据结构hash函数

2010-06-01 15:25:27

JavaCLASSPATH

2020-07-21 08:26:08

SpringSecurity过滤器

2023-09-19 22:47:39

Java内存

2009-06-19 14:10:42

Java多态性

2017-01-10 08:48:21

2017-08-15 13:05:58

Serverless架构开发运维

2020-09-23 10:00:26

Redis数据库命令

2024-02-21 21:14:20

编程语言开发Golang

2019-06-25 10:32:19

UDP编程通信

2019-09-09 09:05:59

图片框架懒加载

2013-09-22 14:57:19

AtWood

2023-10-19 11:12:15

Netty代码

2009-09-25 09:14:35

Hibernate日志

2021-02-17 11:25:33

前端JavaScriptthis

2021-07-22 09:55:28

浏览器前端缓存

2010-03-12 08:55:06

Java内省反射
点赞
收藏

51CTO技术栈公众号