You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Byte Buddy无法对final类java.lang.ProcessBuilder做Advice的解决方案咨询

关于Byte Buddy对final类java.lang.ProcessBuilder执行Advice的问题

我在使用Byte Buddy时,想要对final类java.lang.ProcessBuilder执行Advice操作,但尝试后无法成功。查询资料得知Byte Buddy无法为final修饰的类提供Advice,请问该说法是否属实?有没有可行的解决办法?

我尝试的代码如下:

AgentBuilder agentBuilder = new AgentBuilder.Default()
        .disableClassFormatChanges()
        .with(RETRANSFORMATION)
        .ignore(none())
        .ignore(
                nameStartsWith("net.bytebuddy.")
                        .or(nameStartsWith("jdk.internal.reflect."))
                        .or(nameStartsWith("java.lang.invoke."))
                        .or(nameStartsWith("com.sun.proxy."))
                        .or(nameStartsWith("com.bc.horizon.fuzzing.agent"))
                        .or(nameStartsWith("org.slf4j."))
                        .or(nameStartsWith("io.grpc.netty."))
                        .or(nameContains("javassist"))
                        .or(nameContains("org.jacoco"))
                        .or(nameContains(".asm."))
                        .or(nameContains(".reflectasm."))
        )
        .disableClassFormatChanges()
        .with(RETRANSFORMATION)
        .with(new AgentListener())
        .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
        .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
        .with(AgentBuilder.TypeStrategy.Default.REBASE);

AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, module) -> {
            builder = builder.visit(Advice.to(monitorPlugin.adviceClass()).on(interceptPoint.buildMethodsMatcher()));
            return builder;
        };
agentBuilder = agentBuilder.type(interceptPoint.buildTypesMatcher()).transform(transformer);

我还尝试直接指定java.lang.ProcessBuilder,但仍然失败,代码如下:

System.out.println("Java Agent !");
AgentBuilder agentBuilder = new AgentBuilder.Default()
        .disableClassFormatChanges()
        .with(RETRANSFORMATION)
        .ignore(none())
        .ignore(
                nameStartsWith("net.bytebuddy.")
                        .or(nameStartsWith("jdk.internal.reflect."))
                        .or(nameStartsWith("java.lang.invoke."))
                        .or(nameStartsWith("com.sun.proxy."))
                        .or(nameStartsWith("org.slf4j."))
                        .or(nameStartsWith("io.grpc.netty."))
                        .or(nameContains("javassist"))
                        .or(nameContains("org.jacoco"))
                        .or(nameContains(".asm."))
                        .or(nameContains(".reflectasm.")))
        .disableClassFormatChanges()
        .with(RETRANSFORMATION)
        .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
        .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
        .with(AgentBuilder.TypeStrategy.Default.REBASE);
agentBuilder.type(ElementMatchers.nameStartsWith("java.lang.ProcessBuilder"))
        .transform((builder, typeDescription, classLoader, module) ->
                builder.method(ElementMatchers.isConstructor()).intercept(MethodDelegation.to(MyInterceptor.class)));
agentBuilder.installOn(inst);

解答

说法是否属实?

不完全准确。Byte Buddy本身可以对final类的方法/构造器应用Advice,核心限制不在类的final修饰符上,而是来自两个关键因素:

  • JDK核心类的保护机制:java.lang.ProcessBuilder属于JDK核心类,受JVM模块系统(Java 9+)或安全管理器(旧版本)限制,默认不允许修改。
  • Byte Buddy配置冲突:代码中同时启用REDEFINE和REBASE策略,导致逻辑冲突,无法正确执行类转换。

可行解决办法

1. 调整JVM启动参数,开放核心类修改权限

针对Java 9+,添加以下JVM参数:

--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED

Java 8及以下,需禁用安全管理器或调整权限策略,通常可通过-Xbootclasspath/a:指定代理路径,确保-javaagent代理有足够权限。

2. 修正Byte Buddy配置

  • 移除重复的disableClassFormatChanges()和with(RETRANSFORMATION)调用,避免冗余。
  • 不同时使用REDEFINE和REBASE策略,二选一即可,核心类推荐用REDEFINE。
  • 类匹配规则改为nameEquals("java.lang.ProcessBuilder"),避免匹配无关类。

修正后的示例代码:

System.out.println("Java Agent !");
AgentBuilder agentBuilder = new AgentBuilder.Default()
        .disableClassFormatChanges()
        .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
        .ignore(AgentBuilder.Default.ignore()
                .nameStartsWith("net.bytebuddy.")
                .or(nameStartsWith("jdk.internal.reflect."))
                .or(nameStartsWith("java.lang.invoke."))
                .or(nameStartsWith("com.sun.proxy."))
                .or(nameStartsWith("org.slf4j."))
                .or(nameStartsWith("io.grpc.netty."))
                .or(nameContains("javassist"))
                .or(nameContains("org.jacoco"))
                .or(nameContains(".asm."))
                .or(nameContains(".reflectasm.")))
        .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
        .with(AgentBuilder.TypeStrategy.Default.REDEFINE);

agentBuilder.type(ElementMatchers.nameEquals("java.lang.ProcessBuilder"))
        .transform((builder, typeDescription, classLoader, module) ->
                builder.visit(Advice.to(MyAdvice.class).on(ElementMatchers.isConstructor())));

agentBuilder.installOn(inst);

3. 使用Advice替代MethodDelegation

核心类场景下,Advice比MethodDelegation更轻量、兼容性更好,它直接修改目标方法字节码,无需生成额外类或依赖动态代理。确保Advice类符合规范,示例如下:

public class MyAdvice {
    @Advice.OnMethodEnter
    public static void enter(@Advice.Argument(0) List<String> command) {
        System.out.println("ProcessBuilder构造器被调用,命令:" + command);
    }
}

内容的提问来源于stack exchange,提问作者user9178223

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 17:54:53