使用byte buddy代理修改java.util类

使用byte buddy代理修改java.util类,java,bytecode,threadpoolexecutor,byte-buddy,javaagents,Java,Bytecode,Threadpoolexecutor,Byte Buddy,Javaagents,是否可以使用byte buddy在java.util类中添加字段 我试图在java.util.concurrent.FutureTask中添加一个字段,并截取构造函数和一个任意方法来设置和获取字段值。简而言之,我正在尝试向FutureTask添加一个字段,这样我就可以从父线程向子线程传递一些值,即使它们正在线程池中运行。是否可以在FutureTask中添加字段 未来的任务 @Override protected ElementMatcher.Junction<TypeDescrip

是否可以使用byte buddy在java.util类中添加字段

我试图在java.util.concurrent.FutureTask中添加一个字段,并截取构造函数和一个任意方法来设置和获取字段值。简而言之,我正在尝试向FutureTask添加一个字段,这样我就可以从父线程向子线程传递一些值,即使它们正在线程池中运行。是否可以在FutureTask中添加字段

未来的任务

@Override
    protected ElementMatcher.Junction<TypeDescription> getNarrowTypesMatcher() {
        return named("java.util.concurrent.FutureTask");
    }

    @Override
    public AgentBuilder.Transformer getTransformer() {

        return (builder, typeDescription, classLoader, module) -> {
            beforeTransformation(typeDescription, classLoader);

            return builder
                    .defineField("pit", String.class)
                    .constructor(ElementMatchers.any())
                    .intercept(Advice.to(SetPitAdvice.class))
                    .method(named("run"))
                    .intercept(Advice.to(GetPitAdvice.class))
                    ;
        };

    }
建议

    @Advice.OnMethodEnter
    public static void getValues(@Advice.FieldValue(value = "pit") String pit)
            throws Exception {

        logger.info("pit in future Task {}", pit);
    }

@Advice.OnMethodExit
    public static void setValues(
            @Advice.FieldValue(value = "pit", readOnly = false) String pit
    )
            throws Exception {

        logger.debug("Setting pit field in FutureTask");

        pit = SimulationRequestContextHolder.get("pit");

    }
代理生成器

    private static AgentBuilder createAgentBuilder(AutoEvictingCachingBinaryLocator binaryLocator) {
        final ByteBuddy byteBuddy = new ByteBuddy()
                .with(TypeValidation.of(AgentProperties.PROPERTIES.isDebugInstrumentation()))
                .with(MethodGraph.Compiler.ForDeclaredMethods.INSTANCE);

        return new AgentBuilder.Default(byteBuddy)
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .with(getListener())
                .with(binaryLocator)
                .ignore(any(), ClassLoaderNameMatcher.isReflectionClassLoader())
                .or(any(), ClassLoaderNameMatcher.classLoaderWithName("org.codehaus.groovy.runtime.callsite.CallSiteClassLoader"))
                .or(any(), new IsIgnoredClassLoaderElementMatcher())
                .or(nameStartsWith("org.aspectj.")
                        .or(nameStartsWith("org.groovy."))
                        .or(nameStartsWith("com.sun."))
                        .or(nameStartsWith("com.p6spy."))
                        .or(nameStartsWith("net.bytebuddy."))
                        .or(nameStartsWith("org.slf4j.").and(not(nameStartsWith("org.slf4j.impl."))))
                        .or(nameContains("javassist"))
                        .or(nameContains(".asm."))
                        .or(nameStartsWith("com.java.agent.sims")
                        ))
//                .disableClassFormatChanges()
                .enableUnsafeBootstrapInjection()
                ;
    }
onTransformListener显示类已转换

11:27:24.141 [main] INFO com.java.agent.sims.ApplicationClassLoaderMatcher - Instrumenting ClassLoader null: true
11:27:24.186 [main] DEBUG com.java.agent.sims.transformers.ByteBuddyTransformer - TRANSFORM java.util.concurrent.FutureTask (FutureTaskTransformer)
11:27:24.466 [main] INFO com.java.agent.sims.instrument.TransformListener - Class modified by Byte Buddy: java.util.concurrent.FutureTask

但是我的建议截取没有被调用。

如果类已经加载,这是不可能的。相反,您可以使用
Instrumentation
API将一个类注入引导类加载器,并在该类中存储一个带有弱键的静态映射,在该映射中放置每个实例的字段值

另外,请注意,引导类加载器加载的类无法看到由系统类加载器加载的代理包含的任何类。因此,advice使用的任何API都必须注入引导加载程序