乐趣区

关于java:谈一谈Java类加载相关的方方面面

什么是类加载器

类加载器就是将类的形容加载到虚拟机内存的这样一个模块;典型的类的形容就是 java 源码编译后的 class 文件,也能够是其余任何数据模式,比方网络字节流等;

类加载器有哪些

java 默认定义了三品种加载器:

  • 启动类加载器(Bootstrap Class-Loade)次要加载 jre/lib 上面的 jar 包
  • 扩大类加载器(Extension or Ext Class-Loader)次要加载 jre/lib/ext/ 目录下的 jar 包;(jre/lib/ext/ 目录能够通过指定的 java.ext.dirs 笼罩)
  • 利用类加载器(Application or App Class-Loader),加载 classpath 的内容(classPath 是一组目录组合)。

利用类加载器是能够被“笼罩”的,通过 -Djava.system.class.loader=com.yourcorp.YourClassLoader 整个参数来笼罩原有的利用类加载器;这里的笼罩加了双引号,实际上自定义的类加载器会称为默认利用类加载器的父亲;

个别在须要扭转双亲委派模型的时候会这么做;对于双亲委派模型,看下文;

类加载器的双亲委派模型

什么是双亲委派模型

当类加载器(Class-Loader)试图加载某个类型的时候,除非父加载器找不到相应类型,否则尽量将这个工作代理给以后加载器的父加载器去做。应用委派模型的目标是防止反复加载 Java 类型

为什么采纳双亲委派模型

采纳双亲委派模型次要出于两点思考:

  1. 保障类的唯一性,一个类只被加载一次,防止反复加载;(因为在 JVM 标准外面,同一个 class 文件被两个雷同的类加载,会被视为两个类)
  2. 安全性,保障 java 外围 API 不被替换;也就是启动类加载器加载过的类不会被其余类加载器笼罩;

有哪些突破了双亲委派模型,为什么突破

  • JNDI 服务
  • Tomcat 服务器
  • OSGI 实现热更新

以上场景突破双亲委派模型的起因是父类没有能力加载或者实现所需的一些逻辑,为了整体架构设计更加优雅、灵便,便交由子类加载器来进行加载;

类加载的过程

类加载次要分为三个过程,加载、链接、初始化;

加载:Java 将字节码数据从不同的数据源读取到 JVM 中,并映射为 JVM 认可的数据结构(Class 对象)

链接: 这是外围的步骤,简略说是把原始的类定义信息平滑地转化入 JVM 运行的过程中。具体又细分为验证、筹备、解析三个过程;

  • 验证:验证 Class 对象是否合乎虚拟机标准
  • 筹备:创立动态变量并筹备内存空间
  • 解析:将常量池中的符号援用批改为间接援用

初始化: 执行类的初始化逻辑,包含动态字段赋值,动态块的初始化等;父类型的初始化优先于以后类型的。

自定义类加载器有哪些利用场景

  • 批改类的字节码逻辑,比方:为外部类对立织入通用逻辑;“
  • 依据用户需要,动静的创立类;比方:JDBC 的驱动类,不同数据库须要应用不同的驱动类
  • 包名 + 类名有抵触的时候,一个类加载器不能同时加载,能够用不同的类加载器加载到内存中;
  • 热更新个性,通过自定义类加载器,实现在运行过程中动静的加载、卸载类

自定义类加载器的实现

次要外围在于获取类的字节码阶段,对于将字节码映射为 Class 对象,这部分个别不会波及;

public class CustomClassLoader extends ClassLoader {
 
    @Override
    public Class findClass(String name) throws ClassNotFoundException {byte[] b = loadClassFromFile(name); // 这里是外围逻辑
        return defineClass(name, b, 0, b.length);
    }
 
    private byte[] loadClassFromFile(String fileName)  {InputStream inputStream = getClass().getClassLoader().getResourceAsStream(fileName.replace('.', File.separatorChar) + ".class");
        byte[] buffer;
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        int nextValue = 0;
        try {while ( (nextValue = inputStream.read()) != -1 ) {byteStream.write(nextValue);
            }
        } catch (IOException e) {e.printStackTrace();
        }
        buffer = byteStream.toByteArray();
        return buffer;
    }
}

小结

明天跟大家分享了 java 类加载器的以下常识:

  1. 什么是类加载器
  2. 类加载器具体有哪些
  3. 类加载过程中的双亲委派模型
  4. 类加载的具体过程
  5. 自定义类加载器的利用场景
  6. 类加载器的实现

零根底学习 Java 编程,能够退出我的十年 Java 学习园地,技术交换,资源分享,答疑解惑,开发经验总结。

退出移动版