raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.23k stars 804 forks source link

How to change the loaded class in javaagent? #1607

Closed houxinlin closed 6 months ago

houxinlin commented 6 months ago

This is my code, when I don't use sleep, he can intercept normally

    public static void premain(String agentArgs, Instrumentation inst) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(20000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                for (Class allLoadedClass : inst.getAllLoadedClasses()) {
                    if (allLoadedClass.getName().equals("org.example.ScheduleTest")) {
                        new AgentBuilder.Default()
                                .type(ElementMatchers.named("org.example.ScheduleTest"))
                                .transform((builder, typeDescription, classLoader, module, protectionDomain1)
                                        -> builder.method(ElementMatchers.named("test"))
                                        .intercept(MethodDelegation.to(Interceptor.class)))
                                .installOn(inst);
                    }
                }
            }
        }).start();
    }
raphw commented 6 months ago

If you are registering the interceptor after the program has started, the class will be loaded already.

To instrument loaded classes, have a look at retransformation. This will however also require you to use Advice in most cases.

houxinlin commented 6 months ago

If you are registering the interceptor after the program has started, the class will be loaded already.

To instrument loaded classes, have a look at retransformation. This will however also require you to use Advice in most cases.

Do I need to call the following code?

But this doesn't work either, please advise

  try {
           inst.retransformClasses(allLoadedClass);
  } catch (UnmodifiableClassException e) {
            throw new RuntimeException(e);
 }
houxinlin commented 6 months ago

I want to intercept the specified method again after the class has been loaded

raphw commented 6 months ago

Register a RetransformationStrategy. This will normally require Advice.

houxinlin commented 6 months ago

Is it like this? When "org.example.ScheduleTest" is loaded, it still doesn't work

 new AgentBuilder.Default()
         .type(ElementMatchers.named("org.example.ScheduleTest"))
         .transform((builder, typeDescription, classLoader, module,protectionDomain) -> builder
                 .method(ElementMatchers.any())
                 .intercept(Advice.to(Interceptor.class)))
         .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
         .installOn(inst);
public class Interceptor {
    @Advice.OnMethodEnter
    static long invokeBeforeEachMethod(
            @Advice.Origin String method) {
        System.out.println("Entering to invoke : " + method);
        return System.currentTimeMillis();
    }
    @Advice.OnMethodExit
    static void invokeWhileExitingEachMethod(@Advice.Origin String method,
                                             @Advice.Enter long startTime) {
        System.out.println(
                "Method " + method + " took " + (System.currentTimeMillis() - startTime) + "ms");
    }
}