当前位置:   article > 正文

jvm基础三——类加载器

jvm基础三——类加载器

类加载器

在Java中,类加载器(Class Loader)是Java虚拟机(JVM)的一部分,负责将类文件(.class文件)加载到JVM中,使得程序能够使用这些类。类加载器在Java中具有重要的作用,它的主要任务包括:

  1. 加载(Loading):找到并加载类文件的字节码数据。类加载器根据类的全限定名(Fully Qualified Name)来查找并读取对应的类文件。

  2. 链接(Linking):链接包括验证、准备和解析这三个步骤。

    • 验证(Verification):确保类文件的字节码符合JVM规范,并且安全地加载到JVM中。
    • 准备(Preparation):为类的静态变量分配内存,并设置默认初始值。
    • 解析(Resolution):将符号引用转换为直接引用。
  3. 初始化(Initialization):对类进行初始化,包括执行静态代码块和初始化静态变量等。

Java的类加载器采用了双亲委派模型(Parent Delegation Model)。根据这个模型,当需要加载一个类时,类加载器首先会委派给父类加载器加载,只有在父类加载器无法加载该类时,才会尝试自己加载。这种层次化的类加载器体系保证了类的统一性和安全性,同时也避免了类的重复加载。

Java中的类加载器可以分为以下几种类型:

  1. Bootstrap Class Loader(引导类加载器):是JVM的一部分,它负责加载JVM自身需要的类,包括java.lang包中的类。它是用本地代码(Native Code)实现的,无法直接在Java中获取对其的引用。

  2. Extension Class Loader(扩展类加载器):负责加载Java的扩展库,位于JRE的lib/ext目录下的类。它是由sun.misc.Launcher$ExtClassLoader类实现的,是Bootstrap Class Loader的子类。

  3. Application Class Loader(应用程序类加载器):也叫系统类加载器,负责加载应用程序中的类。它是由sun.misc.Launcher$AppClassLoader类实现的,是Extension Class Loader的子类。

  4. 自定义类加载器:Java允许用户自定义类加载器,继承自java.lang.ClassLoader类,实现自定义的加载逻辑。通过自定义类加载器,可以实现一些特殊的类加载需求,比如从网络、数据库或其他非标准位置加载类。

Java的类加载器机制为Java程序提供了灵活性和安全性,可以根据不同的需求扩展或自定义类加载器,实现各种复杂的类加载逻辑

 

类加载器的双亲委派机制 

Java中的类加载器采用了双亲委派机制(Parent Delegation Model),这是一种类加载器的工作原则,用于保证类加载的统一性和安全性。该机制基于一个简单的原则:除非父类加载器无法加载该类,否则由父类加载器加载。

下面是双亲委派机制的工作流程:

  1. 当一个类加载器收到加载类的请求时,它首先不会自己尝试去加载这个类,而是把请求委托给父类加载器去完成。

  2. 每个类加载器都会把加载请求向上委托给父类加载器,直到达到顶层的引导类加载器(Bootstrap Class Loader)。

  3. 如果父类加载器可以加载这个类,就成功返回;如果父类加载器无法加载,子类加载器才会尝试自己去加载这个类。

这种机制的优势在于确保了Java核心库的一致性:无论哪个类加载器加载一个类,最终被加载的类都是相同的。这样可以避免在不同的类加载器下出现同名类的冲突问题。

双亲委派机制还提高了安全性。因为在这种机制下,Java类的加载都是从根加载器开始的,根加载器只加载标准的核心Java类库,不会加载应用程序的类。这样可以防止应用程序通过替换核心Java类库中的类来破坏JVM的稳定性和安全性。

总的来说,双亲委派机制保证了类加载的一致性、安全性和稳定性,是Java类加载机制的核心之一。

打破

尽管双亲委派机制在大多数情况下都是非常有用的,但在某些特殊情况下,可能需要打破双亲委派机制。打破双亲委派机制通常是为了实现一些特殊的类加载需求,比如热部署、动态更新等。

在Java中,要打破双亲委派机制,一般需要自定义类加载器,并重写其加载类的方法。下面是一种可能的方法:

  1. 自定义类加载器:继承自 ClassLoader 类,并重写 loadClass() 方法

  2. loadClass() 方法中,根据需要的加载策略,决定是否调用父类加载器的 loadClass() 方法。

  3. 如果需要打破双亲委派机制,可以在自定义类加载器的 loadClass() 方法中直接加载指定类,而不是委托给父类加载器。

下面是一个简单的示例代码,演示如何打破双亲委派机制:

  1. public class MyClassLoader extends ClassLoader {
  2. @Override
  3. public Class<?> loadClass(String name) throws ClassNotFoundException {
  4. if (name.startsWith("com.example")) {
  5. // 对于指定的类,直接由自定义类加载器加载
  6. return findClass(name);
  7. }
  8. // 其他类委托给父类加载器加载
  9. return super.loadClass(name);
  10. }
  11. @Override
  12. protected Class<?> findClass(String name) throws ClassNotFoundException {
  13. // 实现自定义的类加载逻辑,比如从文件或网络加载类的字节码数据
  14. // 这里只是一个简单示例,实际应用中需要根据具体需求实现
  15. byte[] classData = getClassData(name);
  16. if (classData == null) {
  17. throw new ClassNotFoundException(name);
  18. }
  19. return defineClass(name, classData, 0, classData.length);
  20. }
  21. // 实现获取类字节码数据的方法,这里只是一个简单示例,实际应用中需要根据具体需求实现
  22. private byte[] getClassData(String name) {
  23. // 从指定的位置获取类字节码数据
  24. // 这里可以是文件、网络等来源
  25. return null;
  26. }
  27. }

在上面的示例中,自定义了一个 MyClassLoader 类继承自 ClassLoader,重写了 loadClass() 方法和 findClass() 方法。在 loadClass() 方法中,指定了对于以 "com.example" 开头的类,直接由自定义类加载器加载,而对于其他类,委托给父类加载器加载。在 findClass() 方法中,实现了加载类的具体逻辑,可以从指定的位置获取类的字节码数据并定义类。

需要注意的是,打破双亲委派机制可能会导致类加载冲突和安全问题,因此应谨慎使用,并确保了解其潜在的影响。

 

 

 

jdk8后类加载器(模块化)

 总结

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/397716
推荐阅读
相关标签
  

闽ICP备14008679号