美文网首页
java之热替换技术

java之热替换技术

作者: 爱编程的凯哥 | 来源:发表于2019-03-11 06:18 被阅读41次

目标

理解热替换技术原理,代码实现

原理

java的类加载机制,主要分为4层


类加载

从上到下,各司其职,BootstrapClassLoader负责加载jre/lib下的核心api或-Xbootclasspath指定的jar,ExtClassLoader负责加载java.ext.dirs,即jre/bin/ext定义的扩展包,AppClassLoader负责加载你指定的web应用的class,最后你自己可以通过CustomClassLoader实现自己定义类加载器,可以用来加载你自己想要加载的class文件.

而热替换正是利用CustomClassLoader来实现自定类的加载实现的.
根据双亲委派模式, CustomClassLoader要加载某个类也会从上向下加载,而我们为了实现热替换,对于我们需要热替换的类,完全不需要遵循这种双亲委派模式.
我们只需要,在更新此类文件时,生成一个新的CustomClassLoader,重新加载对应的需要替换类,然后用他来替换原有CustomClassLoader加载的有类(tomcat的热部署也是类似这种机制).

demo实例

附上demo源码:git@gitee.com:kaiyang_taichi/hot_replacement_demo.git ,测试类里放的就是我们用来热升级的TestCall类

image.png

demo解释

  1. 定义HotDeployFactory类,用于加载自定义类,此工厂通过静态方法init进行初始化加载所需要的类, upgrade进行升级使用,此时会重新生成对应的currentClassLoader类,加载最新的Call类.
package com.example.hotdeploy.hot;

import java.io.*;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @Description: 需要热替换的服务类工厂
 * @Author: kai.yang
 * @Date: 2019-03-10 07:13
 */
public class HotDeployFactory {

    /**
     * 正在使用的classloader
     */
    private static ClassLoader currentClassLoader;

    private static String[] needHotClasses;

    private static AtomicBoolean inited = new AtomicBoolean(false);


    /**
     * 默认加载根目录
     */
    private static String javaRoot = "/Users/kai.yang/Desktop/java-test/hot/";


    public static void init(String... needHotClasses) {
        HotDeployFactory.inited.compareAndSet(false, true);
        HotDeployFactory.currentClassLoader = new hotClassLoader(javaRoot, needHotClasses);
        HotDeployFactory.needHotClasses = needHotClasses;
    }

    public static void upgrade() {
        if (inited.get()){
            HotDeployFactory.currentClassLoader = new hotClassLoader(HotDeployFactory.javaRoot, needHotClasses);
        }else{
            throw new RuntimeException("非法异常");
        }
    }

    public static Object getObject(String className) throws Exception {
        Class<?> aClass = currentClassLoader.loadClass(className);
        return aClass.newInstance();
    }

    /**
     * 自定义classloader类
     */
    static class hotClassLoader extends ClassLoader {

        private String baseDir;

        private HashSet<String> myClasses = new HashSet<>();

        public hotClassLoader(String baseDir, String[] classNames) {
            super(null);
            this.baseDir = baseDir;
            loadDir(classNames);
        }


        private void loadDir(String[] classNames) {
            if (classNames == null || classNames.length == 0) {
                return;
            } else {
                for (String clazz : classNames) {
                    try {
                        StringBuilder sb = new StringBuilder(baseDir);
                        sb.append(clazz.replace(".", File.separator)).append(".class");
                        loadClazz(clazz, new File(sb.toString()));
                        myClasses.add(clazz);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }


        private Class loadClazz(String name, File file) throws IOException {
            InputStream inputStream = new FileInputStream(file);
            byte[] raw = new byte[(int) file.length()];
            inputStream.read(raw);
            return defineClass(name, raw, 0, (int) file.length());
        }


    }


}

  1. 使用是定义在service层,因为没有实现父类加载器加载接口方法,demo中用反射调用此方法,可参考文末链接学习
public class FeeServiceImpl implements FeeService {

    private static final String CallClass="TestCall";

    static{
        HotDeployFactory.init("TestCall");
    }



    @Override
    public String callUserFee(BigDecimal amount, String feeRate) throws Exception {
        Object object = HotDeployFactory.getObject(CallClass);
        Method call = object.getClass().getMethod("call", BigDecimal.class, String.class);
        Object invoke = call.invoke(object, amount, feeRate);
        return invoke.toString();
    }
}
  1. 定义TestCall类,因为我们现在只加载class文件,不处理java文件,所以手动编译java类

public class TestCall {


    public String call(BigDecimal amount, String feeRule) {

        return amount.add(new BigDecimal(feeRule)).toString();
    }
}

编译后

kaiyangdeMacBook-Pro-2:hot kai.yang$ javac TestCall.java 
kaiyangdeMacBook-Pro-2:hot kai.yang$ ls
TestCall.class  TestCall.java

4.启动springboot服务,访问api

@Controller
@RequestMapping("/api")
public class BillController {

    @Autowired
    FeeService feeService;

    @RequestMapping("/fee/{amount}/{feerate}")
    @ResponseBody
    public String test(@PathVariable String amount, @PathVariable String feerate) {
        try {
            return feeService.callUserFee(new BigDecimal(amount), feerate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "fail";
    }

    @RequestMapping("/up")
    @ResponseBody
    public String upgrade() {
        HotDeployFactory.upgrade();
        return "ok";
    }
}

访问url,http://localhost:8888/api/fee/11/10,显示结果:

加法结果
  1. 手动修改TestCall.java类,改为
public class TestCall {


    public String call(BigDecimal amount, String feeRule) {

        return amount.multiply(new BigDecimal(feeRule)).toString();
    }
}

重新编译java类


重新编译

调用升级api:http://localhost:8888/api/up

5.重新调用http://localhost:8888/api/fee/11/10

乘法结果

好了,热替换完成了!

参考资料:https://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/index.html

相关文章

  • java之热替换技术

    目标 理解热替换技术原理,代码实现 原理 java的类加载机制,主要分为4层 从上到下,各司其职,Bootstra...

  • 热修复之AndFix探秘

    热修复之AndFix探秘 近几年热修复技术可谓百花齐放,阿里的底层结构替换即时生效技术AndFix,后来又出来看起...

  • Vue脚手架热更新技术探秘

    Vue脚手架热更新技术探秘 前言 热替换(Hot Module Replacement)或热重载(Hot Relo...

  • 今日份打卡 182/365

    技术文章不重启JVM,替换已加载的类!Java方法存储区,能够实现替换的基础!Instrumentation接口A...

  • Andfix Android之热修复

    什么是热修复技术?AndFix框架替换原理和优势... 什么是热修复技术? 当我们已上线的app出现了非常影响用户...

  • Android热修复系列(二):代码热修复技术原理

    上篇讲到代码修复技术分为两类:底层替换热修复和类加载热修复。这篇主要是对这两者底层原理的学习。 一、底层替换热修复...

  • Java热部署技术

    1 Java热部署 1.1 热部署问题 在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java ...

  • webpack之热更新/替换

    模块热替换(HMR)什么是模块热替换HMR(Hot Module Replacement),在应用程序运行过程中,...

  • 笔记 深入探索Android热修复技术原理

    阿里电子书《深入探索Android热修复技术原理》整理的笔记 1.热修复技术介绍 代码修复两大主要方案底层替换方案...

  • android高级知识汇总

    原文地址 公共技术点之 Android 动画基础公共技术点之 Java 动态代理公共技术点之依赖注入公共技术点之 ...

网友评论

      本文标题:java之热替换技术

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