动态更改JVM里的class
来源:互联网 发布:数据库管理员简历 编辑:程序博客网 时间:2024/05/22 00:21
近来需要完成一个feature:修改已load到JVM中的某个class,对其加一些代码,以此来动态修改运行中的程序。
对着这个feature我找到的方案是agent+Instrumentation+ASM
一路做下来有以下几点比较有意思:
1)动态attach agent到某个JVM进程
一般使用agent都是静态的,直接在运行某程序时加agent参数,这样agent会先于程序启动,这个不符合我的需求,我找到一个动态attach agent的方法,具体细节见以下代码:
- public static void attach(String pid) throws Exception {
- try {
- String agentPath = "/cutemock-agent.jar";
- String tmp = Main.class.getClassLoader().getResource("com/taobao/lp/cutemock/agent/Main.class").toString();
- tmp = tmp.substring(0, tmp.indexOf("!"));
- tmp = tmp.substring("jar:".length(), tmp.lastIndexOf("/"));
- agentPath = tmp + agentPath;
- agentPath = new File(new URI(agentPath)).getAbsolutePath();
- VirtualMachine vm = null;
- if (debug) {
- debugPrint("attaching to " + pid);
- }
- vm = VirtualMachine.attach(pid);
- if (debug) {
- debugPrint("attached to " + pid);
- }
- if (debug) {
- debugPrint("loading " + agentPath);
- }
- String agentArgs = "port=" + port;
- if (debug) {
- agentArgs += ",debug=true";
- }
- if (debug) {
- debugPrint("agent args: " + agentArgs);
- }
- vm.loadAgent(agentPath, agentArgs);
- if (debug) {
- debugPrint("loaded " + agentPath);
- }
- } catch (RuntimeException re) {
- throw re;
- } catch (IOException ioexp) {
- throw ioexp;
- } catch (Exception exp) {
- throw exp;
- }
- }
这段代码的关键是要找到agent的jar包,然后通过VirtualMachine.attach和VirtualMachine.loadAgent把agent attach到pid上
2)通过Instrumentation修改已load了的class
见如下代码:
- Class[] classes = inst.getAllLoadedClasses();
- for(Class clazz : classes){
- if(clazz.getName().equals(CLASS_NAME)){
- System.out.println("add transformer to TBRemotingRPCProtocolComponent.class");
- inst.addTransformer(new MyClassFileTransformer(),true);
- inst.retransformClasses(clazz);
- }
- }
关键在于inst.addTransformer(new MyClassFileTransformer(),true);这个true参数,inst.retransformClasses(clazz);只会重新修改addTransformer中canRetransform==true的
3)通过asm eclipse plugin方便修改class
大家都知道可以通过asm来修改class,但其api及其难用,比如我仅仅只想加一行:
targetURL = MockUtil.getTargetUrl(metadata.getUniqueName(), request.getMethodName(), targetURL);
翻译为asm:
- mv.visitVarInsn(Opcodes.ALOAD, 2);
- mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/taobao/hsf/model/metadata/ServiceMetadata", "getUniqueName", "()Ljava/lang/String;");
- mv.visitVarInsn(Opcodes.ALOAD, 1);
- mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/taobao/hsf/domain/HSFRequest", "getMethodName", "()Ljava/lang/String;");
- mv.visitVarInsn(Opcodes.ALOAD, 3);
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/taobao/lp/cutemock/agent/MockUtil", "getTargetUrl", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
- mv.visitVarInsn(Opcodes.ASTORE, 3);
- Label l4 = new Label();
- mv.visitLabel(l4);
但asm提供了一个eclipse plugin,更新地址为:http://andrei.gmxhome.de/eclipse/
它可以对比出修改前后的class的差异,并自动翻译为asm代码
以上是我这两天玩动态修改class的一些心得,有点乱,但确实是不断尝试后的心得
- 动态更改JVM里的class
- 动态更改JVM里的class
- 动态更改class属性
- 使用javassist框架进行动态的更改Class类
- 从JVM中dump出动态代理生成的class
- 如何动态更新JVM中的class文件
- JVM寻找Class的顺序
- JVM 加载.class的过程
- JVM的class文件结构
- JVM加载class的原理
- Java虚拟机(JVM)的动态类加载(Class Loading)
- Java虚拟机(JVM)的动态类加载(Class Loading)
- Java虚拟机(JVM)的动态类加载(Class Loading)
- 在Eclipse中配置动态加载Class的JVM插件--JavaRebel
- 在Eclipse中配置动态加载Class的JVM插件--JavaRebel
- jvm里的内存区域
- C++里的计数器class
- 更改eclipse中JVM的内存大小
- terminal 不能敲 s 键
- REDHAT解决apt-get问题
- 从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(三)
- 黑马程序员-基础-IO流1
- Java动态执行可配置的逻辑
- 动态更改JVM里的class
- tar.gz文件的安装
- BST中所有结点之和(设结点个数为n,且中序遍历为等差数列)
- 九度oj1081递推数列的算法
- 通通WPF随笔(3)——艺术二维码素材生成器
- ubuntu下的wireshark编译安装
- cocos2d-x学习之路(8)--重构项目
- 黑马程序员-基础-IO流2
- DIV CSS left right top bottom定位