思路
当一个java的类文件发生变更,如果动态的热更新这个新的类文件?目前来说,有两种可能的方式
- 新增一个自定义ClassLoader,名为NC,让NC去load这个新的类文件,这样就完成了新的类定义的替换
- 但目前Java有一种特性:
ClassLoader不支持卸载一个已装载的类,且ClassLoader是基于双亲委派机制来加载一个类的字节码文件的
。这就导致一个问题,自定义的ClassLoader应该更新一个名为findClass
的父类方法,让自定义的ClassLoader不要向父级ClassLoader去询问这个类是否已加载过,否则就会抛出企图重复定义同名类的异常。 - 如何保证所有对象都经过自定义ClassLoader去加载?目前来说,可以通过JDK 7中引入的
WatchService
的方式,监听项目中的class文件变更,获取其字节码文件,让其通过自定义ClassLoader去loadClass
,这种方式用来动态更新类定义的弊端过大,每次类文件发生变更,就需要新建一个ClassLoader去loadClass
- 但目前Java有一种特性:
- 通过
javaagent
的方式,创建Transformer
,通过Instrumentation
对象提供的redefineClasses
方法,用这种方式,将监听到的类文件变更后的字节码文件,转为byte[]
格式,让其重新定义,这种方式相比较第一种方法更为高效可靠。
Galois 通过监听项目代码变更,使用 redefineClasses 方法来重新装载类,并通过 ASM 侵入 SpringBoot 框架 和 MyBatis 框架核心代码的方式,获取到能重新装载
Bean
或Mapper
的核心对象,以此实现项目的代码热部署更新。