美文网首页程序员
类加载器与类的热替换(Hotswap)

类加载器与类的热替换(Hotswap)

作者: 侯树成 | 来源:发表于2017-02-20 22:50 被阅读1261次

在Java 应用开发中,经常会有的一个问题,需要在应用正在运行的过程中,把一个新实现的功能加到class中,并且不能停止当前的应用运行。也就是说,要实现类的热替换(Hotswap)。这一点,在Java Web应用中体现的更为明显,每次更新配置,更新class,都需要重新启动服务器,重新加载这些改动,这一过程相当耗时。

那为什么不在应用服务器运行时,或者说Java的应用运行过程中,把class替换后实时生效呢?

这一点,是和Class的生命周期密切相关的。

任何一个使用到的Class,都需要被classLoader加载到JVM中,这个加载的过程,又分为

  • defineClass

  • loadClass

  • resolveClass

即根据提供的不同形式的class文件的内容,转化成一个Class,对其进行加载,链接。

而所谓的hotswap,就是使用新的代码替换掉已经加载的这个Class中的内容。

我们这里使用Javassist来模拟类似的效果,通过动态的修改class内某个方法的内容,来实现热替换的效果。

基本步骤:
先定义一个接口,包含一个方法,该方法内的内容在后面用于热替换

定义一个接口的实现

在Servlet内接收页面上传入的参数,页面上的参数内容,则是具体上面接口定义方法及方法对应的方法体内容

在接收到参数后,根据参数内容,使用Javassist进行热替换的操作。

基本Javassist的代码大概是下面的样子:

ITemp test = new Temp();  // 声明一个接口
ClassPool pool = new ClassPool(true);

private ITemp hotswap(String str) {
        String methodBody = null;
        try {
  //添加到classpath
            pool.insertClassPath(new ClassClassPath(ITemp.class));
            String className = "ITemp_" + UUID.randomUUID();

            CtClass clazz = pool.makeClass(className);
            clazz.setInterfaces(new CtClass[]{pool.get("com.xxxx.ITemp")});
            methodBody = str;
            clazz.addMethod(CtMethod.make(methodBody, clazz));

            ITemp fun = (ITemp) clazz.toClass().newInstance();
            calculatorClass.writeFile("d:/temp");
            return fun;

            } catch(Exception e) {
            
            }

在用的过程中,接收到参数后,把hotswap方法返回的实例再指给test这个实例。然后test内对应方法的执行已经改成在页面上传入的逻辑。

原理

上面的是怎么样实现的呢?

其实,上面的替换,实质上,是重新生成了一个ITemp这个接口的实现类,然后我们在页面上定义的,是这个实现类的方法中的内容。然后我们的替换,是把一个实现类的引用改成另一个。

在更新Server中service的引用,指向新的实现,旧的会在引用请求执行完成后会被释放。

另外一个

这时,一定有同学提起JDK默认支持的 Agent,这种基于JVMTI的实现。但是,这里需要注意的是,此时使用的是Agent,如果使用其pre_main,那么支持的是Class的 defineClass执行前,对其进行所谓的增强或者是织入,类似于OpenJPA的Enhance和AJP的weave。
这种相当于是把class内容在读到内容之后修改了一下,然后传给classLoader进行defineClass。

而JVMTI在JDK1.6之后,支持的另外一种形式,是在应用已经部署启动之后,要进行类的改变的,使用的是agent_main方法,此时,需要对class进行retransform。像Java里一些常用的Profiler工具使用的就是这种,attach到已经启动的Java进程,对其进行retransform,例如Btrace。

这里的transform会调用Instrumention的RedefineClass,本质上是修改类的定义。我们以Btrace为例,来看他在背后做了什么。

我的Trace脚本内容如下:

@BTrace(unsafe=true)
public class TracingScript {
@OnMethod(clazz="com.xxx.WorkFun", method="myPrint")
public void sc() {
    println("===========");
  }
}

对于要监控的类WorkFun,我们看到,Btrace监控后,会类内新增一个方法$btrace$TracingScript$sc()

该方法就所做的就是我们在Trace脚本里定义的内容,比如上面,我们会在对应java方法执行时打印一行等号,其对应的方法jvm指令如下:

而这个方法是如何和我们自己要监控的方法联系起来的呢?就是在我们的监控方法第一行,增加了对于trace方法的调用。

其他热替换的内容,想起来再补充。

相关文章

  • 类加载器与类的热替换(Hotswap)

    在Java 应用开发中,经常会有的一个问题,需要在应用正在运行的过程中,把一个新实现的功能加到class中,并且不...

  • 类加载阅读目录

    什么是类加载器 类加载器与类的”相同“判断 类加载器种类 双亲委派模型 类加载过程 自定义类加载器 JAVA热部署...

  • 透过现象看本质:Java类动态加载和热替换

    摘要:本文主要介绍类加载器、自定义类加载器及类的加载和卸载等内容,并举例介绍了Java类的热替换。 最近,遇到了两...

  • JVM-类加载器

    JVM-类加载器 类与类加载器 对于类与类加载器有两种限定: 对于任意一个类,都需要由加载它的类加载器和这个类本身...

  • 《深入理解JVM虚拟机》读书笔记-类加载器&Java模块化系统

    类加载器 一.类加载器 1.1 类与类加载器 类加载器的定义: Java虚拟机设计团队有意把 类加载阶段中 的“ ...

  • Java类加载

    本篇笔记的目标是理解类加载器的架构,学会实现类加载器并理解热替换的底层原理。 什么是类加载 类从被加载到虚拟机内存...

  • 热修复类加载项目实战

    android 与 java 的类加载器 类别加载文件类加载器分类java.class 文件{{java类加载机制...

  • JVM类加载器子系统ClassLoader

    1 类加载器与类的加载过程 类加载器子系统的作用:类加载子系统负责从文件或者网络中加载class文件,class文...

  • java类加载器及其原理

    java类加载器 : java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器(也叫应用类加载器) ...

  • Java classpath

    一、类加载器与classpath 以下为系统中的三种类加载器,每个类加载器都有自己用来寻找类文件的路径。其中系统类...

网友评论

    本文标题:类加载器与类的热替换(Hotswap)

    本文链接:https://www.haomeiwen.com/subject/maqywttx.html