Java热更新


一、  解决方案

1)  自定义类加载器。

首先需要明白一点,class相等的判断条件不仅仅是类名相同,还需要加载它的ClassLoader相同。JVM内部规定一个ClassLoader不可以重复定义类,也就是说想要重定义一个类,就必须使用一个全新的ClassLoader。

JVM内部class被卸载的条件及其苛刻,甚至没有明确的方法可以直接调用,只有当加载该类型的类加载器实例为unreachable状态时,也就是没有任何实例,class才有可能被卸载。(启动类加载器实例永远为reachable状态,由启动类加载器加载的类型可能永远不会被卸载)

<span style="white-space:pre">	</span>public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
		Class<?> clazz = null;
		// 首先检查请求的类型是否已经被这个类装载器装载到命名空间中了,如果已经装载,直接返回;否则继续。
		if (name.startsWith("com.wafer") || name.contains("Service")) {
			if (resolve) {
				resolveClass(clazz); // 链接指定的 Java 类
			}
			// 如果class类被修改过,则重新加载
			MoeLoader hcl = new MoeLoader(url);
			clazz = customLoad(name, hcl);
			return (clazz);
		}
		// 如果类的包名为"java."开始,则有系统默认加载器加载
		try {
			// 得到系统默认的加载cl
			ClassLoader system = ClassLoader.getSystemClassLoader();
			clazz = system.loadClass(name); // 加载名称为 name的类
			if (clazz != null) {
				if (resolve)
					resolveClass(clazz);
				return (clazz);
			}
		} catch (ClassNotFoundException e) {
			// Ignore
		}
		return customLoad(name, this);
	}


此范例的核心在于缓存自己已经加载的class,当再次需要加载时,如果发生变更,则可以new一个ClassLoader,这样新的字节码便可以即时生效。

JRbel是一种热更新的方案,它实现的方式是通过在启动参数中添加javaagent,即JVM底层提供的Instrumentation技术,来改变生成对象的方式。

2)  JVMTI虚拟机工具接口

JPDA是 Java 平台调试体系结构的缩写。通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。 JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI)、Java 调试线协议(JDWP),以及 Java 调试接口(JDI)。参考资源(http://www.ibm.com/developerworks/cn/views/java/libraryview.jsp?search_by=深入+Java+调试体系)

<span style="white-space:pre">	</span>List<Connector> connectors =    Bootstrap.virtualMachineManager().allConnectors();
		SocketAttachingConnector sac = null;
		for (Connector connector : connectors) {
			if (connector instanceof SocketAttachingConnector) {
				sac = (SocketAttachingConnector) connector;
			}
		}
		if (sac != null) {
			Map<String, Connector.Argument> defaultArguments = sac.defaultArguments();
			Connector.Argument hostArg = defaultArguments.get("hostname");
			Connector.Argument portArg = defaultArguments.get("port");
			hostArg.setValue("localhost");
			portArg.setValue("8787");
			VirtualMachine vm = sac.attach(defaultArguments);

			List<ReferenceType> rtList = vm.classesByName("com.wafer.demo.jdi.Foo");
			ReferenceType rt = rtList.get(0);
			Map<ReferenceType, byte[]> newByteCodeMap = new HashMap<ReferenceType, byte[]>(1);
			//获取特定类的字节码,发送到虚拟机
			byte[] newByteCode = genNewByteCodeUsingJavassist();
			newByteCodeMap.put(rt, newByteCode);

			if (vm.canRedefineClasses()) {
				vm.redefineClasses(newByteCodeMap);
			}
		}


Eclipse的热更新实现的方式便是如此,以Debug启动时,Eclipse会在JVM参数中添加-agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:63597,之后检测到代码变更时,将变更的字节码通过jdwp发送到应用。

BTrace可以发送字节码到应用,对拦截的类进行监控,其实现的方式同样用到JVMTI。使用VirtualMachine.attach(pid)连接到应用。

### Java热更新的实现方法与工具 Java 热更新(Hot Reload)是一种允许开发者在不重启应用程序的情况下动态加载修改后的类文件的技术。这种技术对于提高开发效率非常有用,尤其是在调试复杂的应用程序时。 #### 方法一:JRebel JRebel 是一种流行的商业工具,用于支持 Java 应用程序的实时代码更改应用。通过 JRebel,开发者可以在运行时替换已编译的类文件而无需重新启动 JVM 或容器。这显著减少了开发周期时间,并提高了生产力[^4]。 ```java // 修改后的代码可以立即生效而不需重启服务 public class Example { public static void main(String[] args) { System.out.println("This message can be updated without restarting."); } } ``` #### 方法二:Spring Loaded Spring Loaded 是一个开源项目,旨在提供类似于 JRebel 的功能。它能够检测到源码的变化并自动刷新受影响的类实例。尽管它的功能可能不如 JRebel 那么全面,但对于许多 Spring 和非 Spring 项目来说已经足够强大[^5]。 #### 方法三:使用 JDK 自带的功能——`Instrumentation` Java 提供了一个名为 `java.lang.instrument` 的包,该包允许在运行时改变字节码的行为。利用这个特性,开发者可以通过自定义代理来实现简单的热部署机制。然而,这种方法通常较为复杂且容易出错[^6]。 ```java import java.lang.instrument.Instrumentation; public class Agent { private static Instrumentation instrumentation; public static void premain(String agentArgs, Instrumentation inst) { instrumentation = inst; } public static void transformClass(Class<?> targetClass, byte[] newByteCode) { if (instrumentation != null && !instrumentation.isModifiableClass(targetClass)) { throw new IllegalArgumentException("Cannot modify class: " + targetClass.getName()); } else { instrumentation.redefineClasses(new ClassDefinition[]{new ClassDefinition(targetClass, newByteCode)}); } } } ``` #### 方法四:OSGI 动态模块化框架 OSGi 技术提供了另一种形式的热插拔能力,即它可以让你随时安装、卸载或者更新单个 bundle 而不影响整个系统的正常运作。虽然 OSGi 主要设计目标并非单纯为了简化开发过程中的快速迭代需求,但它确实具备这样的潜力[^7]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值