java热更实例

java热更实例

热更实现

  1. 新建一个java项目,编写一个类ClassReloader.java实现public static void premain(String agentArgs, Instrumentation inst)方法
  2. 打成jar,修改MANIFEST.MF
  3. 启动服务器的时候jvm参数要加一行,jar路径可以是相对路径 -javaagent:C:/jow/LoadTest/test.jar
  4. 在自己需要热更功能的项目中新写一个类ClassReloadManager.java,新增一个方法public static void reload(String path)传入需要热更的class路径,注意这个路径必须是类的全路径(包含包路径),调用ClassReloader.reload()
  5. 写一个test试试

热更案例

  • 新建空项目,编写一个类agent.ClassReloader.java.
package agent;
public class ClassReloader {
	// 热更句柄
	private static Instrumentation inst = null;

	// 初始化
	public static void premain(String agentArgs, Instrumentation inst) {
		ClassReloader.inst = inst;
	}
   // 热更类
	public static void reload(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException {
		inst.redefineClasses(definitions);
	}
}

导出jar包test.jar,然后修改jar包中的MANIFEST.MF
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Premain-Class: agent.ClassReloader  //指定全路径
Can-Redefine-Classes: true //指定为true,可以重新定义类
Created-By: 14.1-b02 (Sun Microsystems Inc.)
Boot-Class-Path: test.jar  //指定jar包的路径,全路径或者相对路径都可以
  • 新建一个空项目编写两个类ClassReloadManager.java和Test.java
package main;
import agent.ClassReloader;

public class ClassReloadManager {

	public static void reload() throws ClassNotFoundException, IOException, UnmodifiableClassException {
		reload("jowC");
	}

	public static void reload(String path) throws ClassNotFoundException, IOException, UnmodifiableClassException {
		ClassReloader.reload(readAllClass(path));
	}

	/**
	 * 读取filePath目录下的所有class文件,并根据类的全路径读取class信息
	 */
	public static ClassDefinition[] readAllClass(String filePath) throws ClassNotFoundException, IOException {
		// Log.game.info("start read Class,dir path= : " + filePath);
		System.out.println("start read Class,dir path= : " + filePath);

		List<File> files = new ArrayList<>();
		readClassFiles(filePath, files);
		ClassDefinition[] result = new ClassDefinition[files.size()];
		for (int i = 0; i < files.size(); i++) {
			File file = files.get(i);
			String url = file.getAbsolutePath().replace("bin", "@");
			url = url.substring(url.indexOf('@') + 1).replaceAll("\\\\", ".").replaceAll("/", ".");
			String forName = url.substring(1, url.length() - 6);
			// Log.game.info("read class:" + forName);
			Class<?> clazz = Class.forName(forName);
			result[i] = new ClassDefinition(clazz, readClassBuffer(file));
		}
		return result;
	}

	public static void readClassFiles(String path, List<File> result) {
		File dir = new File(path);
		if (!dir.exists() || !dir.isDirectory())
			return;

		File[] dirFiles = dir.listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return file.isDirectory() || file.getName().endsWith(".class");
			}
		});

		for (File file : dirFiles) {
			if (file.isDirectory()) {
				readClassFiles(file.getAbsolutePath(), result);
			} else {
				result.add(file);
			}
		}
	}

	public static byte[] readClassBuffer(File classFile) throws IOException {
		byte[] buffer = new byte[(int) classFile.length()];
		FileInputStream fis = new FileInputStream(classFile);
		BufferedInputStream bis = new BufferedInputStream(fis);

		try {
			bis.read(buffer);
		} catch (IOException arg7) {
			throw arg7;
		} finally {
			bis.close();
		}

		return buffer;
	}
}

  • Test
package main;

public class Test {

	public static void main(String[] args) throws Exception {
		talk();
		ClassReloadManager.reload("C:/classhotfix");
		talk();
	}

	public static void talk() {
	   // System.out.println("miao miao miao");
		System.out.println("wang wang wang");
	}
}

  • 运行。编译两个Test,不同的是talk方法输出的内容不同,然后放到C:/classhotfix目录下最后路径应该是:classhotfix/main/Test.java。修改jvm启动参数-javaagent:C:/jow/LoadTest/test.jar
  • 输出
wang wang wang
miao miao miao
  • 最后
    1.如果项目已经在运行中了,则ClassReloader应该实现public static void agentmain(String agentArgs, Instrumentation inst);方法。通过绑定pid来热更。
    2.我经历过的项目里热更出现过宕机。尝试过jdk1.8.144 jdk1.8.152 jdk1.8.192。每个版本都说它修复了ciObjectFactory::create_new_metadata,但是每个版本都宕过机,每次宕机都去看官网,都说在之后的版本修复了……
    https://bugs.openjdk.java.net/browse/JDK-8134389,然而没有。但是jdk9不敢用在线上项目,真的头疼。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值