JVM--类加载器

概念

类加载器:只参与加载过程中的字节码获取并加载到内存中的部分;java虚拟机提供给应用程序去实现获取类和接口字节码数据的一种技术,也就是说java虚拟机是允许程序员写代码去获取字节码信息

类加载是加载的第一步,主要有以下三个步骤:

(1)通过全类名获取定义此类的二进制字节流;

(2)将字节码文件的静态存储结构转换成方法区运行时的数据结构;

(3)在内存中生成一个该类的class对象,作为方法区的访问入口;

类加载器:

(1)类加载器是负责加载类的一个对象,用于类加载中加载这一步;

(2)每一个java类都有一个引用指向加载他的ClassLoader;

(3)数组类不是通过ClassLoader创建的(数组类没有对应的二进制字节流),是有jvm直接生成的

其实除了加载类之外,类加载器还可以加载 Java 应用所需的资源如文本、图像、配置文件、视频等等文件资源。本文只讨论其核心功能:加载类。

类加载器的分类

(1)jvm底层源码实现:实现语言和虚拟机底层语言一致,比如Hotspot使用C++。主要目的是保证Java程序运行中基础类被正确地加载,比如java.lang.String,Java虚拟机需要确保其可靠性。

(2)java代码实现:jdk默认提供的类加载器,或者是程序员按照需求定制,所有java实现的类加载类都需要继承classloader这个抽象类。

jdk8以前:

启动类加载器

  • 启动类加载器(Bootstrap ClassLoader)是由Hotspot虚拟机提供的、使用C++编写的类加载器。

  • 默认加载Java安装目录/jre/lib下的类文件,比如rt.jar,tools.jar,resources.jar等。

java 复制代码
/**
 * 启动程序类加载器案例
 */
public class BootstrapClassLoaderDemo {
    public static void main(String[] args) throws IOException {
        ClassLoader classLoader = String.class.getClassLoader();
        System.out.println(classLoader);

        System.in.read();
    }
}

上面的代码打印出来的类加载器为null,因为启动类加载器在jdk8中是由c++来编写的,在java代码中获取不安全,所以返回了null。

如果用户想扩展一些比较基础的jar包,让启动类加载器加载,有两种途径:

  • 放入jre/lib下进行扩展。不推荐,尽可能不要去更改JDK安装目录中的内容,会出现即时放进去由于文件名不匹配的问题也不会正常地被加载。

  • **使用参数进行扩展。**推荐,使用-Xbootclasspath/a:jar包目录/jar包名 进行扩展,参数中的/a代表新增。

扩展类加载器和应用程序加载器

(1)扩展类加载器和应用程序加载器都是由jdk提供,使用java代码编写;

(2)它们的源码都位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader(具备通过目录或者指定jar包将字节码文件加载到内存中)

扩展类加载器

扩展类加载器(Extension Class Loader)是JDK中提供的、使用Java编写的类加载器。默认加载Java安装目录/jre/lib/ext下的类文件。

java 复制代码
/**
 * 扩展类加载器
 */
public class ExtClassLoaderDemo {
    public static void main(String[] args) throws IOException {
        ClassLoader classLoader = ScriptEnvironment.class.getClassLoader();
        System.out.println(classLoader);
    }
}

通过扩展类加载器去加载用户jar包:

  • 放入/jre/lib/ext下进行扩展。不推荐,尽可能不要去更改JDK安装目录中的内容。

  • 使用参数进行扩展使用参数进行扩展。推荐,使用-Djava.ext.dirs=jar包目录 进行扩展,这种方式会覆盖掉原始目录,可以用;(windows):(macos/linux)追加上原始目录

如下图中:

使用引号将整个地址包裹起来,这样路径中即便是有空格也不需要额外处理。路径中要包含原来ext文件夹,同时在最后加上扩展的路径。

应用程序加载器

java 复制代码
/**
 * 应用程序类加载器案例
 */
public class AppClassLoaderDemo {
    public static void main(String[] args) throws IOException, InterruptedException {
        //当前项目中创建的Student类
        Student student = new Student();
        ClassLoader classLoader = Student.class.getClassLoader();
        System.out.println(classLoader);

        //maven依赖中包含的类
        ClassLoader classLoader1 = FileUtils.class.getClassLoader();
        System.out.println(classLoader1);

        Thread.sleep(1000);
        System.in.read();

    }
}

双亲委派机制

概念:

向上检查是加载过这个类,向下加载;在类加载的过程中,每个类加载器都会先检查是

否已经加载了该类,如果已经加载则直接返回,否则会将加载请求委派给父类加载器。

例子:

B类在扩展类加载器加载路径中,同样应用程序类加载器接到了加载任务,按照案例1中的方式一层一层向上查找,发现都没有加载过。那么启动类加载器会首先尝试加载。它发现这类不在它的加载目录中,向下传递给扩展类加载器。

如果第二次再接收到加载任务,同样地向上查找。扩展类加载器发现已经加载过,就可以返回了。

作用:

1.保证类加载的安全性。通过双亲委派机制避免恶意代码替换JDK中的核心类库,比如

java.lang.String,确保核心类库的完整性和安全性。

2.避免重复加载。双亲委派机制可以避免同一个类被多次加载。

打破双亲委派机制:

(1)自定义类加载器;

(2)线程上下文加载器;

(3)osgi框架的类加载器;

相关推荐
Fanxt_Ja2 小时前
【JVM】三色标记法原理
java·开发语言·jvm·算法
要睡觉_ysj3 小时前
JVM 核心概念深度解析
jvm
lanfufu5 小时前
记一次诡异的线上异常赋值排查:代码没错,结果不对
java·jvm·后端
全都是浮夸丶5 小时前
JVM知识
jvm
河南第一深情彭于晏7 小时前
jvm学习第1day jvm简介,栈溢出、堆溢出
jvm
Thanwind7 小时前
JVM中的各类引用
java·jvm·jmm
异常君9 小时前
JVM 新生代垃圾回收:避免全堆扫描的核心技术
java·jvm
异常君9 小时前
深入理解 JVM 中的 Concurrent Mode Failure:原因、影响与解决策略
java·jvm
吾日三省吾码12 小时前
深入解析 Java ClassLoader:揭开 JVM 动态加载的神秘面纱
java·jvm
懋学的前端攻城狮12 小时前
深入浅出JVM-03:Java虚拟机垃圾回收机制详解
java·jvm·后端