Java 中什么情况下类会被重载?

2023-04-10 19:34:45 +08:00
 biuaxia

项目中有一个类 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 给重载了呢?如果要改的话怎么入手?

1950 次点击
所在节点    Java
11 条回复
kyrieIvring
2023-04-10 21:31:58 +08:00
一 看 classloader 是不是优先加载你这个 class ,如果是 强行改 classloader 的顺序
二 看这个 class 是不是被编译进各个系统 jar 包里面了,如果是,你要找到对应的 jar 包,修改一下,再把它放回原来的位置
biuaxia
2023-04-11 07:37:19 +08:00
@kyrieIvring 确定不是 classloader 导致的,利用类加载机制覆盖也没法。
biuaxia
2023-04-11 07:38:44 +08:00
@kyrieIvring 贴出来的代码都是从三方 jar 包中反编译出来的,然后运行时通过阿里 arthas(可能拼错)运行 jad 得到的源码
huyangq
2023-04-11 09:07:58 +08:00
不理解,什么叫类会被重载?我就知道函数(或者说方法、method)重载(overload)
huyangq
2023-04-11 09:13:57 +08:00
仔细又阅读了一下,你的意思是有一个类 PluginStarter ,直接反编译 jar 包,发现改类中的 start()、end()的实现逻辑是 A ,但是当运行之后,如果执行到一行代码:new Sigar()之后,类 PluginStarter 中的 start()、end()的实现逻辑却成了 B 。
huyangq
2023-04-11 09:14:47 +08:00
如果是这样,结合你的依赖包 asm 猜测是运行时修改了字节码实现的
biuaxia
2023-04-11 09:50:31 +08:00
@huyangq 是的,如果是运行时修改字节码,有什么方式可以实现我想要的修改吗?
huyangq
2023-04-11 09:55:53 +08:00
你可以先确认是不是改的字节码,既然你说执行 new Sigar()会修改函数实现,你可在执行 new Sigar()之前、之后调用一下 start()、end()用来确定是否真的在 Sigar 构造函数中修改了函数实现,然后,再去看 Sigar 构造函数的实现 看看里头是不是真的又修改函数实现的代码,如果有,那简单啊 执行构造函数之后,再改成你要的函数实现就可以了
vvtf
2023-04-11 09:59:57 +08:00
看下 java-agent 吧,
是用 instrumentation 实现的.
dif
2023-04-11 10:56:49 +08:00
有个成熟的监控项目 pinpoint 用到了类似的技术,你可以参考下。都是通过 java-agent 实现的。
Aresxue
2023-04-11 21:58:48 +08:00
类不会重载,只是会被 retransform ,简而言之就是方法体里面的字节码会被替换掉,JVMTI 提供了这样的机制,一般都是各种 agent 在启动时就会修改指定方法的字节码,不过也有些剑走偏锋直接在框架中用 asm 或者 javasist 修改的,像 HikariCP 就使用了各种字节码的黑魔法,可以看下有没有使用这两个框架的 api 的地方

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/931344

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX