Java-热加载实现

本文介绍了Java热加载的概念,对比了热加载和热部署,详细解析了Java类加载机制,探讨了如何通过自定义类加载器实现热加载,并讨论了优化方案,以提升开发效率并确保安全性。
摘要由CSDN通过智能技术生成

什么是热加载

热加载是指可以在不重启服务的情况下让更改的代码生效

热加载可以显著的提升开发以及调试的效率,它是基于 Java 的类加载器实现的,但是由于***热加载的不安全性,一般不会用于正式的生产环境***。

热加载 VS 热部署

热加载和热部署,都可以在不重启服务的情况下编译/部署项目,都是基于 Java 的类加载器实现的。

部署方式

  • 热部署在运行时重新部署整个项目;
  • 热加载在运行时重新加载class;

实现原理

  • 热部署是在运行时重新部署整个应用,耗时相对较高;
  • 热加载是在运行时重新加载class,后台启动一个线程检测类的改变;

使用场景

  • 热部署通常在生产环境使用;
  • 热加载通常在开发环境使用,线上由于安全性问题不会使用,难以监控

准备

Java类加载机制

Java类生命周期:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载,前5个为类加载阶段。

类加载的 5 个阶段中,只有加载阶段是用户可以自定义处理的,而验证阶段、准备阶段、解析阶段、初始化阶段都是 JVM 来处理的。

截图

加载

加载阶段,JVM做3件事:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

官方定义的类加载器有3个,通过双亲委派机制确定加载顺序:

截图

类加载器 加载路径
BootstrapClassLoader 处于类加载器层次结构的最高层,负责 sun.boot.class.path 路径下类的加载,默认为 jre/lib 目录下的核心 API 或 -Xbootclasspath 选项指定的 jar 包
ExtClassLoader 加载路径为 java.ext.dirs,默认为 jre/lib/ext 目录或者 -Djava.ext.dirs 指定目录下的 jar 包加载
AppClassLoader 加载路径为 java.class.path,默认为环境变量 CLASSPATH 中设定的值。也可以通过 -classpath 进行指定

默认情况下,使用关键字new或者Class.forName都是通过AppClassLoader类加载器来加载的

默认情况下如果要加载一个类,会优先将此类交给其父类进行加载(直到顶层的BootstrapClassLoader),如果父类都无法加载,那么才会将此类交给子类加载。

截图

验证

确保字节码是安全的,确保不会对虚拟机的安全造成危害

准备

确定内存布局,确定内存遍历,赋初始值(注意:是初始值,也有特殊情况)

解析

将符号引用变成直接引用。

初始化

调用程序自定义的代码。规定有且仅有5种情况必须进行初始化:

  1. new(实例化对象)、getstatic(获取类变量的值,被final修饰的除外,他的值在编译器时放到了常量池)、putstatic(给类变量赋值)、invokestatic(调用静态方法) 时会初始化;
  2. 调用子类的时候,发现父类还没有初始化,则父类需要立即初始化;
  3. 虚拟机启动,用户要执行的主类,主类需要立即初始化,如 main 方法;
  4. 使用 java.lang.reflect包的方法对类进行反射调用方法,会初始化;
  5. 当使用JDK 1.7的动态语言支持时, 如果一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic、 REF_putStatic、 REF_invokeStatic的方法句柄, 且这个方法句柄所对应的类没有进行过初始化, 则需要先触发其初始化;

如何实现热加载

自定义类加载器

需要自定义类加载器。

为啥需要自定义类加载器

为啥需要自定义类加载器,为什么不能使用AppClassLoader或者ExtClassLoader实现热加载呢?

ClassLoader源码:

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
   
    synchronized (getClassLoadingLock(name)) {
   
        // First, check if the class has already been loaded
        //确认该类是否已加载,JVM是以 类加载器实例 + 类文件 来表示同一个类
        //若这个类被不同类加载器加载,findLoadedClass也还是返回未加载
        //所以后面需要每次重新生成类加载器实例
        Class<?> c = findLoadedClass(name);
        if (c == null) {
   
            long t0 = System.nanoTime();
            try {
   
                if (parent != null) {
   
                    c = parent.loadClass(name, false);
                } else {
   
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
   
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值