当前位置: 首页 > article >正文

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等。

/**
 * 启动程序类加载器案例
 */
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下的类文件。

/**
 * 扩展类加载器
 */
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文件夹,同时在最后加上扩展的路径。

应用程序加载器

/**
 * 应用程序类加载器案例
 */
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框架的类加载器;


http://www.kler.cn/a/525298.html

相关文章:

  • 【go语言】gorm 快速入门
  • 解锁豆瓣高清海报:深度爬虫与requests进阶之路
  • 开发环境搭建-4:WSL 配置 docker 运行环境
  • Base64详解
  • 【NLP251】NLP RNN 系列网络
  • Flutter_学习记录_基本组件的使用记录
  • 超越传统图结构:记忆模拟新突破
  • C语言从入门到进阶
  • 【deepseek】本地部署DeepSeek R1模型:使用Ollama打造个人AI助手
  • 并发编程 - 线程同步(二)
  • 【2024年华为OD机试】 (A卷,200分)- 服务中心选址(JavaScriptJava PythonC/C++)
  • Python异步编程核武器:asyncio.gather() 的终极使用手册
  • 使用scikit-learn中的KNN包实现对鸢尾花数据集或者自定义数据集的的预测。
  • SpringBoot+Vue的理解(含axios/ajax)-前后端交互前端篇
  • 【开源免费】基于SpringBoot+Vue.JS社区智慧养老监护管理平台(JAVA毕业设计)
  • gif动画图像优化,相同的图在第2,4,6帧中重复出现,会增加图像体积吗?
  • 迭代推理机制提升AI精准性
  • 一文简单回顾Java中的String、StringBuilder、StringBuffer
  • 【阅读笔记】基于图像灰度梯度最大值累加的清晰度评价算子
  • Python里的小整数问题挺有意思的
  • 【NLP251】NLP RNN 系列网络
  • pytorch线性回归模型预测房价例子
  • 乐优商城项目总结
  • AI大模型开发原理篇-3:词向量和词嵌入
  • Ubuntu 16.04安装Lua
  • Yii框架中的正则表达式:如何实现高效的文本操作