
项目中有一个类 cn.qy.fk.util.PluginStarter, 当 org.hyperic.sigar.Sigar 的对象被 new 出来时, PluginStarter 整个类的方法都会被重载, 完整的代码我都贴在下面, 想问下大佬们我如果要修改方法内容, 应该如何操作呢?
想要修改方法的类 cn.qy.fk.util.PluginStarter (从 jar 包中反译得来):
package cn.qy.fk.util; @CustomFunction( type = 7 ) public class PluginStarter { public PluginStarter() { } public boolean start() { return (boolean)null; } public void end() { } } 项目运行时 cn.qy.fk.util.PluginStarter 实际的源码为:
package cn.qy.fk.util; import cn.qy.fk.util.CustomFunction; import cn.qy.fk.util.SystemProperties; @CustomFunction(type=7) public class PluginStarter { public boolean start() { String error; if ((error = SystemProperties.get((String)"error")) != null) { System.out.println(error); return false; } System.out.println("Plugin Context is starting ..."); return true; } public void end() { System.out.println("Plugin Context was started!"); } } 注解 cn.qy.fk.util.CustomFunction (从 jar 包中反编译得来):
package cn.qy.fk.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface CustomFunction { int type(); } 项目中用到了:
我通过 IDEA 的断点发现每当代码执行到了下面的 new Sigar(); 时类就被重载了.
try { Sigar sigar = new Sigar(); (new PluginStarter()).start(); } 项目的资源目录还发现了:
libsigar-amd64-freebsd-6.so libsigar-amd64-linux.so libsigar-amd64-solaris.so libsigar-ia64-hpux-11.sl libsigar-ia64-linux.so libsigar-pa-hpux-11.sl libsigar-ppc64-aix-5.so libsigar-ppc64-linux.so libsigar-ppc-aix-5.so libsigar-ppc-linux.so libsigar-s390x-linux.so libsigar-sparc64-solaris.so libsigar-sparc-solaris.so libsigar-universal64-macosx.dylib libsigar-universal-macosx.dylib libsigar-x86-freebsd-5.so libsigar-x86-freebsd-6.so libsigar-x86-linux.so libsigar-x86-solaris.so sigar-amd64-winnt.dll sigar-x86-winnt.dll sigar-x86-winnt.lib 想问下这种是不是被 jni 给重载了呢?如果要改的话怎么入手?
1 kyrieIvring 2023-04-10 21:31:58 +08:00 一 看 classloader 是不是优先加载你这个 class ,如果是 强行改 classloader 的顺序 二 看这个 class 是不是被编译进各个系统 jar 包里面了,如果是,你要找到对应的 jar 包,修改一下,再把它放回原来的位置 |
2 biuaxia OP @kyrieIvring 确定不是 classloader 导致的,利用类加载机制覆盖也没法。 |
3 biuaxia OP @kyrieIvring 贴出来的代码都是从三方 jar 包中反编译出来的,然后运行时通过阿里 arthas(可能拼错)运行 jad 得到的源码 |
4 huyangq 2023-04-11 09:07:58 +08:00 不理解,什么叫类会被重载?我就知道函数(或者说方法、method)重载(overload) |
5 huyangq 2023-04-11 09:13:57 +08:00 仔细又阅读了一下,你的意思是有一个类 PluginStarter ,直接反编译 jar 包,发现改类中的 start()、end()的实现逻辑是 A ,但是当运行之后,如果执行到一行代码:new Sigar()之后,类 PluginStarter 中的 start()、end()的实现逻辑却成了 B 。 |
6 huyangq 2023-04-11 09:14:47 +08:00 如果是这样,结合你的依赖包 asm 猜测是运行时修改了字节码实现的 |
8 huyangq 2023-04-11 09:55:53 +08:00 你可以先确认是不是改的字节码,既然你说执行 new Sigar()会修改函数实现,你可在执行 new Sigar()之前、之后调用一下 start()、end()用来确定是否真的在 Sigar 构造函数中修改了函数实现,然后,再去看 Sigar 构造函数的实现 看看里头是不是真的又修改函数实现的代码,如果有,那简单啊 执行构造函数之后,再改成你要的函数实现就可以了 |
9 vvtf 2023-04-11 09:59:57 +08:00 看下 java-agent 吧, 是用 instrumentation 实现的. |
10 dif 2023-04-11 10:56:49 +08:00 有个成熟的监控项目 pinpoint 用到了类似的技术,你可以参考下。都是通过 java-agent 实现的。 |
11 Aresxue 2023-04-11 21:58:48 +08:00 类不会重载,只是会被 retransform ,简而言之就是方法体里面的字节码会被替换掉,JVMTI 提供了这样的机制,一般都是各种 agent 在启动时就会修改指定方法的字节码,不过也有些剑走偏锋直接在框架中用 asm 或者 javasist 修改的,像 HikariCP 就使用了各种字节码的黑魔法,可以看下有没有使用这两个框架的 api 的地方 |