这篇文章主要讲解了“java类加载器与类的热替换怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java类加载器与类的热替换怎么实现”吧!
成都创新互联专注于乳源网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供乳源营销型网站建设,乳源网站制作、乳源网页设计、乳源网站官网定制、微信小程序服务,打造乳源网络公司原创品牌,更为您提供乳源网站排名全网营销落地服务。
任何一个使用到的Class,都需要被classLoader加载到JVM中,这个加载的过程,又分为
defineClass
loadClass
resolveClass
即根据提供的不同形式的class文件的内容,转化成一个Class,对其进行加载,链接。
而所谓的hotswap,就是使用新的代码替换掉已经加载的这个Class中的内容。
我们这里使用Javassist来模拟类似的效果,通过动态的修改class内某个方法的内容,来实现热替换的效果。
基本步骤:
先定义一个接口,包含一个方法,该方法内的内容在后面用于热替换
定义一个接口的实现
在Servlet内接收页面上传入的参数,页面上的参数内容,则是具体上面接口定义方法及方法对应的方法体内容
在接收到参数后,根据参数内容,使用Javassist进行热替换的操作。
基本Javassist的代码大概是下面的样子:
ITemp test = new Temp(); // 声明一个接口
ClassPool pool = new ClassPool(true);
private ITemp hotswap(String str) {
String methodBody = null;
try {
//添加到classpath
pool.insertClassPath(new ClassClassPath(ITemp.class));
String className = "ITemp_" + UUID.randomUUID();
CtClass clazz = pool.makeClass(className);
clazz.setInterfaces(new CtClass[]{pool.get("com.xxxx.ITemp")});
methodBody = str;
clazz.addMethod(CtMethod.make(methodBody, clazz));
ITemp fun = (ITemp) clazz.toClass().newInstance();
calculatorClass.writeFile("d:/temp");
return fun;
} catch(Exception e) {
}
在用的过程中,接收到参数后,把hotswap方法返回的实例再指给test这个实例。然后test内对应方法的执行已经改成在页面上传入的逻辑。
原理
上面的是怎么样实现的呢?
其实,上面的替换,实质上,是重新生成了一个ITemp这个接口的实现类,然后我们在页面上定义的,是这个实现类的方法中的内容。然后我们的替换,是把一个实现类的引用改成另一个。
在更新Server中service的引用,指向新的实现,旧的会在引用请求执行完成后会被释放。
另外一个
这时,一定有同学提起JDK默认支持的 Agent,这种基于JVMTI的实现。但是,这里需要注意的是,此时使用的是Agent,如果使用其pre_main,那么支持的是Class的 defineClass执行前,对其进行所谓的增强或者是织入,类似于OpenJPA的Enhance和AJP的weave。
这种相当于是把class内容在读到内容之后修改了一下,然后传给classLoader进行defineClass。
而JVMTI在JDK1.6之后,支持的另外一种形式,是在应用已经部署启动之后,要进行类的改变的,使用的是agent_main方法,此时,需要对class进行retransform。像Java里一些常用的Profiler工具使用的就是这种,attach到已经启动的Java进程,对其进行retransform,例如Btrace。
这里的transform会调用Instrumention的RedefineClass,本质上是修改类的定义。我们以Btrace为例,来看他在背后做了什么。
我的Trace脚本内容如下:
@BTrace(unsafe=true)
public class TracingScript {
@OnMethod(clazz="com.xxx.WorkFun", method="myPrint")
public void sc() {
println("===========");
}
}
对于要监控的类WorkFun,我们看到,Btrace监控后,会类内新增一个方法$btrace$TracingScript$sc()
该方法就所做的就是我们在Trace脚本里定义的内容,比如上面,我们会在对应java方法执行时打印一行等号,其对应的方法jvm指令如下:
而这个方法是如何和我们自己要监控的方法联系起来的呢?就是在我们的监控方法第一行,增加了对于trace方法的调用。
感谢各位的阅读,以上就是“java类加载器与类的热替换怎么实现”的内容了,经过本文的学习后,相信大家对java类加载器与类的热替换怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!
售后响应及时
7×24小时客服热线数据备份
更安全、更高效、更稳定价格公道精准
项目经理精准报价不弄虚作假合作无风险
重合同讲信誉,无效全额退款