JAVA热部署探究

热部署是在不重启 Java 虚拟机的前提下,能自动侦测到 class 文件的变化,更新运行时 class 的行为。Java 类是通过 Java 虚拟机加载的,某个类的 class 文件在被 classloader 加载后,会生成对应的 Class 对象,之后就可以创建该类的实例。

1、热部署现状

热部署一直以来是一个难以解决的问题,目前java虚拟机只能实现方法体的修改热部署,对整个类的结构修改,仍需要重启。osgi的出现,让模块重启变得可行,但是对于模块之间存在调用关系的情况,会出现短暂的功能性休克。


本文讲述如何实现整个类的热部署


2、类加载细节

虚拟机默认只是在启动的时候加载class文件,如果有个类需要更新的话,单纯替换编译后的class文件,虚拟机是不会重新加载的,要实现热部署,最根本的方式就是修改虚拟机的源代码,让虚拟机监测class文件的变化,如果发生更新就重新加载类。但是这样会破坏jvm的性能。埋下隐患。

另外,就是创建自己的classLoader来加载需要监听的class。

下面来简单列举一下需要做的工作。

  • 创建自定义的 classloader,加载需要监听改变的类,在 class 文件发生改变的时候,重新加载该类 
  • 改变创建对象的行为,使他们在创建时使用自定义 classloader 加载的 class。
 既然在类加载器中,java类只能被加载一次,并且无法卸载。那是不是可以直接把类加载器给换了?答案是可以的,我们可以自定义类加载器,并重写ClassLoader的findClass方法。想要实现热部署可以分以下三个步骤:

1、销毁该自定义ClassLoader
2、更新class类文件
3、创建新的ClassLoader去加载更新后的class类文件。

package com.csair.soc.hotswap;

import java.io.IOException;
import java.io.InputStream;
/**
 * 自定义类加载器,并override findClass方法
 */
public class MyClassLoader extends ClassLoader{
     @Override
     public Class<?> findClass(String name) throws ClassNotFoundException{
            try{
                String fileName = name.substring(name.lastIndexOf("." )+1) + ".class" ;
                InputStream is = this.getClass().getResourceAsStream(fileName);
                 byte[] b = new byte[is.available()];
                is.read(b);
                 return defineClass(name, b, 0, b. length);
           } catch(IOException e){
                 throw new ClassNotFoundException(name);
           }
     }
}

需要更新的类文件:
package com.csair.soc.hotswap;
public class HelloWorld {
     public void say(){
           System. out.println( "Hello World V1");
     }
}
在工程的根目录下,生成V2版本的HelloWorld.class,内容如下。
package com.csair.soc.hotswap;
public class HelloWorld {
      public void say(){
           System. out.println( "Hello World V2");
     }
}

测试主程序

package com.csair.soc.hotswap;

import java.io.File;
import java.lang.reflect.Method;

public class Hotswap {
     public static void main(String[] args) throws Exception {
            loadHelloWorld();
            // 回收资源,释放HelloWorld.class文件,使之可以被替换
           System. gc();
           Thread. sleep(1000);// 等待资源被回收
           File fileV2 = new File( "HelloWorld.class");
           File fileV1 = new File(
                      "bin\\com\\csair\\soc\\hotswap\\HelloWorld.class" );
           fileV1.delete(); //删除V1版本
           fileV2.renameTo(fileV1); //更新V2版本
           System. out.println( "Update success!");
            loadHelloWorld();
     }

     public static void loadHelloWorld() throws Exception {
           MyClassLoader myLoader = new MyClassLoader(); //自定义类加载器
           Class<?> class1 = myLoader
                     .findClass( "com.csair.soc.hotswap.HelloWorld");//类实例
           Object obj1 = class1.newInstance(); //生成新的对象
           Method method = class1.getMethod( "say");
           method.invoke(obj1); //执行方法say
           System. out.println(obj1.getClass()); //对象
           System. out.println(obj1.getClass().getClassLoader()); //对象的类加载器
     }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值