博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JAVA代码热替换HotSwap技术
阅读量:6939 次
发布时间:2019-06-27

本文共 3149 字,大约阅读时间需要 10 分钟。

hot3.png

一、原理:使用不同类加载器,加载的同名类文件,在JVM中并是不同的Class对象

同一个类加载器,对于同一个类名(如:com.xxx.Test),只能加载一次

当输入:a时,类加载器为:

新实例化出来的HotSwapClassLoader加载器的父加载器==》HotSwapClassLoader.class.getClassLoader()

此处为:App class loader

当输入:b或者c时,类加载器为:

新实例化出来的HotSwapClassLoader加载器本身,加载方法为:

defineClass(null, classByte, 0,classByte.length)

重点:每个类加载器对象,自身有一个已加载Class对象池

子加载器,委托父加载器,加载的,二者池中均有此类对象

父加载器自己加载的类对象,子加载器,可以自己另行再加载一个“同名”类对象

图 1. 类加载器树状组织结构示意图

类加载器树状组织结构示意图

二、类加载器的代理模式

类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。在介绍代理模式背后的动机之前,首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。

比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器ClassLoaderA和 ClassLoaderB分别读取了这个 Sample.class文件,并定义出两个 java.lang.Class类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。下面通过示例来具体说明。

三、示例共有三个类

1、主类

import java.io.BufferedReader;import java.io.InputStreamReader;import java.lang.reflect.Method;public class Test {    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        HotSwapClassLoader classloader = new HotSwapClassLoader();        while (true) {            String str = br.readLine();            if (str.equals("0")) {                break;            } else if (str.equals("a")) {            } else {                classloader = new HotSwapClassLoader();                /**                 * 以下注释为,本次测试重点信息                 */                // 下面一行:类加载器在尝试自己去查找某个类的字节代码并定义它时,                // 会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推                // 也就是说:如存在此行时,下一行,就报错                // java.lang.LinkageError: loader (instance of                // HotSwapClassLoader): attempted duplicate class definition for                // name: "MainTest"                // Class clazz = Class.forName("MainTest", true, classloader);                classloader.loadByPath("C:/Users/michael/Desktop/file/temp/" + str + "/MainTest.class");            }            Class clazz = Class.forName("MainTest", true, classloader);            Method method = clazz.getMethod("main", new Class[] { String[].class });            method.invoke(null, new String[] { null });        }    }}

2、类加载器

import java.io.FileInputStream;import java.io.InputStream;public class HotSwapClassLoader extends ClassLoader {    public HotSwapClassLoader() {        super(HotSwapClassLoader.class.getClassLoader());        System.out.println(HotSwapClassLoader.class.getClassLoader());    }    public Class loadByte(byte[] classByte) {        return defineClass(null, classByte, 0, classByte.length);    }    public Class loadByPath(String filePath) throws Exception {        InputStream is = new FileInputStream(filePath);        byte[] b = new byte[is.available()];        is.read(b);        is.close();        return defineClass(null, b, 0, b.length);    }}

3、需要热替换的测试类

public class MainTest {	/**	 * @param args	 */	public static void main(String[] args) {		System.out.println("AAAAAAAAAAAAAAAAAAA");	}}

转载于:https://my.oschina.net/hanshubo/blog/372325

你可能感兴趣的文章
Swift与OC之间的一些不同
查看>>
七.获取真实的DOM节点
查看>>
SQL viewId 比较好看的 Id
查看>>
use include to read a file
查看>>
虚拟属性
查看>>
利用background-attachment做视差滚动效果
查看>>
许小年:宁可踏空,不可断粮<转>
查看>>
第三篇 第八章泡沫灭火系统(二)
查看>>
MYSQL explain 详解
查看>>
移动web-bootstrap
查看>>
洛谷1108 低价购买
查看>>
LeetCode Next Permutation
查看>>
[转载] 杜拉拉升职记——12 话不投机
查看>>
HTTP中的Session和Cookie浅析
查看>>
Java Note
查看>>
台北出差备忘
查看>>
Treap 实现名次树
查看>>
SSD 单发多框检测
查看>>
Layout 不可思议(二)—— 两侧定宽的三列布局
查看>>
Node.js学习笔记(八) --- Node.js的路由模块封装
查看>>