![0ba7c0c6f9dc3fa58a12eaaad05fd633.png](https://i-blog.csdnimg.cn/blog_migrate/e03764306ee7ed25a03cd55d7ac2d227.jpeg)
游戏上线后难免会有功能性bug,这些bug很多只做一些小的改动即可修复。设想假如每次有bug修复之后,都要重启服务器,势必会导致部分玩家流失,对游戏产生不好的影响。在这个背景下,代码热更新还是很有必要的。这里,我们来讨论一种java代码热更新的实现。
代码热更-开源工具的实现
1.Apache Tomcat 实现:
Tomcat 动态 JSP 编译运行,这是一种阉割的热加载。Tomcat 采用ecj (eclise-jdt)组件动态编译jsp生成servlet类,servlet是有固定模板。相对于只改变方法,使用自定义JspLoader 重新创建一个实例的方式运行。普通类和Servlet 本身不行,如修改需要触发context reload (自动重启)
2.Eclipse实现
Eclipse 调试模式下的代码热更,由IDE 内部实现,实际使用的是java agent技术。
代码热更-javaAgent实现
JavaAgent 是JDK 1.5 以后引入的。java.lang.instrument
Agent技术,解决以下两个问题:
1. Java程序启动之前修改类,即main()方法执行前
通过指令java -javaagent:<jarpath>[=<选项>] 触发以下接口
public static void premain(String agentArgs, Instrumentation inst)
2. Java程序运行时修改类
通过新启一个程序获取目标
VirtualMachine virtualmachine = VirtualMachine.attach(jvm_pid);
virtualmachine.loadAgent(agentJarPath, agentParam); 触发下面接口
public static void agentmain (String agentArgs, Instrumentation inst)
作为agent jar 文件需要定义 MANIFEST.MF 属性
Manifest-Version: 1.0
Agent-Class: com.cyou.xyj.agent.ReloadAccountAgent
Premain-Class: com.cyou.xyj.agent.ReloadAccountAgent
Can-Redine-Classes: true
Can-Retransform-Classes: true
Instrumentation 类
void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
boolean removeTransformer(ClassFileTransformer transformer)
void redefineClasses(ClassDefinition... definitions) // 重定义类
boolean isModifiableClass (Class<?> theClass);
void appendToBootstrapClassLoaderSearch(JarFile jarfile)
// 应用。运行时远程加载类库,核心类库不公开
// 运行时扩展功能 etc..
…
ClassFileTransformer 类,唯一接口
// loader 类加载器
// classBeingRedefined 是否允许重定义
// classfileBuffer 原类的字节码
byte[]transform(ClassLoader loader,String className,Class<?> classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer)
类转化的实际逻辑就是创建一个ClassFileTransformer实例,并覆写此方法
![40069e1de45913487eee692e47442ec6.png](https://i-blog.csdnimg.cn/blog_migrate/6672a6af6a2fd1783a1e5c33cf0bba95.jpeg)
![676c18e0d9684ecbaf9e7742119376dd.png](https://i-blog.csdnimg.cn/blog_migrate/3234e4e02cdb457dce34f996e26f9906.jpeg)
![f7101bd0731b6e0ae86f5900dad2614d.png](https://i-blog.csdnimg.cn/blog_migrate/c679b791f9d5f9e114fe7ad5fc32b39c.jpeg)
Account类中修改后的方法被修改。代码热更新完成
通过 –XX:+TraceClassLoading 输出如下
![f711d5024b9e63d3e76582633c9356f2.png](https://i-blog.csdnimg.cn/blog_migrate/e036055698b3ac0de513e226bb45d657.jpeg)