一 代码结构图
二 代码
1 被动态替换的类
package chapter04.java1;
/**
* replaced class
*/
public class Demo1 {
public void hot() {
// System.out.println("OldDemo1"); // A:old class print
// System.out.println("NewDemo1"); // B:new class print
}
}
2 自定义类加载器
package chapter04.java1;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
/**
* 自定义类的加载器
*/
public class MyClassLoader extends ClassLoader {
private String rootDir;
public MyClassLoader(String rootDir) {
this.rootDir = rootDir;
}
protected Class<?> findClass(String className) throws ClassNotFoundException {
Class clazz = this.findLoadedClass(className);
FileChannel fileChannel = null;
WritableByteChannel outChannel = null;
if (null == clazz) {
try {
String classFile = getClassFile(className);
FileInputStream fis = new FileInputStream(classFile);
fileChannel = fis.getChannel();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
outChannel = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while (true) {
int i = fileChannel.read(buffer);
if (i == 0 || i == -1) {
break;
}
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
byte[] bytes = baos.toByteArray();
clazz = defineClass(className, bytes, 0, bytes.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileChannel != null)
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (outChannel != null)
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return clazz;
}
/**
* 类文件的完全路径
*/
private String getClassFile(String className) {
return rootDir + "/" + className.replace('.', '/') + ".class";
}
}
3 测试类
package chapter04.java1;
import java.lang.reflect.Method;
public class LoopRun {
public static void main(String args[]) {
while (true) {
try {
// 1. 创建自定义类加载器的实例
String rootDir = "E:\\jvmp2\\";
MyClassLoader loader = new MyClassLoader(rootDir);
// 2. 加载指定的类
Class clazz = loader.findClass("chapter04.java1.Demo1");
// 3. 创建运行时类的实例
Object demo = clazz.newInstance();
// 4. 获取运行时类中指定的方法
Method m = clazz.getMethod("hot");
// 5. 调用指定的方法
m.invoke(demo);
Thread.sleep(5000);
} catch (Exception e) {
System.out.println("not find");
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
三 测试
1 仅让 Demo1 的 B 处代码生效,编译 Demo1.java
E:\jvmp2\chapter04\java1>javac Demo1.java
2 运行 main,此时控制台打印如下
NewDemo1
NewDemo1
NewDemo1
NewDemo1
3 过上一段时间,仅让 Demo1 的 A 处代码生效,编译 Demo1.java,此时控制台打印如下
NewDemo1
NewDemo1
NewDemo1
NewDemo1
OldDemo1
OldDemo1
OldDemo1
OldDemo1
4 打印发生了变化,说明热替换生效。