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
相关产品推荐
相关产品推荐

