25 Eylül 2023 Pazartesi

Byte Buddy AgentBuilder Sınıfı

Giriş
Gnellikle şu şekilde kullanılır
AgentBuilder.Default()
.type(...)
.transform(...)
.installOn(...)
Çalıştırılacak kod pre-main olarak düşünülür. 

Örnek
Şöyle yaparız. Burada @Repeat olarak işaretli metod 3 kere çağrılıyor
public class Repeater {

  public static void premain(String arguments, Instrumentation instrumentation) {      //1
    var withRepeatAnnotation = 
      isAnnotatedWith(named("ch.frankel.blog.instrumentation.Repeat")); 	       //2
    new AgentBuilder.Default()                                                         //3
      .type(declaresMethod(withRepeatAnnotation))                                      //4
      .transform((builder, typeDescription, classLoader, module, domain) -> builder    //5
        .method(withRepeatAnnotation)                                                  //6
        .intercept(                                                                    //7
           SuperMethodCall.INSTANCE                                                    //8
            .andThen(SuperMethodCall.INSTANCE)
            .andThen(SuperMethodCall.INSTANCE))
      ).installOn(instrumentation);                                                    //3
  }
}
Açıklaması şöyle
1. Required signature; it’s similar to the main method, with the added Instrumentation argument
2. Match that is annotated with the @Repeat annotation. The DSL reads fluently even if you don't know it (I don't).
3. Byte Buddy provides a builder to create the Java agent
4. Match all types that declare a method with the @Repeat annotation
5. Transform the class accordingly
6. Transform methods annotated with @Repeat
7. Replace the original implementation with the following
8. Call the original implementation three times
Sonra şöyle yaparız. Burada bir fat jar oluşturuluyor
<plugin>
  <artifactId>maven-assembly-plugin</artifactId>                       
  <configuration>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>  
    </descriptorRefs>
    <archive>
      <manifestEntries>
        <Premain-Class>ch.frankel.blog.instrumentation.Repeater</Premain-Class>
      </manifestEntries>
    </archive>
  </configuration>
  <executions>
    <execution>
        <goals>
          <goal>single</goal>
        </goals>
      <phase>package</phase>
    </execution>
  </executions>
</plugin>
ve şöyle yaparız
// create the agent
mvn install

// Run the app with the agent:
java 
  -javaagent:/~/.m2/repository/.../agent-1.0-SNAPSHOT-jar-with-dependencies.jar \ #1
  -cp ./target/classes                                                            #2
  ch.frankel.blog.instrumentation.Main                                          

Örnek
Elimizde şöyle bir kod olsun. Bu instrumentation için kullanılacak kod. Bu koddaki premain metodu jvm'den önce çalışır. TimeFooter sınıfı Advice içindir. transform() metoduyla Advice metodlara takılır
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class SimpleInstru {
  public static void premain(String argument,Instrumentation instrumentation) {

    System.out.println("Agent started at " + System.currentTimeMillis());

    Advice advice = Advice.to(TimeFooter.class);
    new AgentBuilder.Default()
      .type(ElementMatchers.nameContains("ApplicationBeingTransformed"))
      .transform((DynamicType.Builder<?> builder,
                TypeDescription type,
                  ClassLoader loader,
                  JavaModule module) -> {
                    return builder.visit(advice.on(ElementMatchers.isMethod()));
      }).installOn(instrumentation);
    }

    public static class TimeFooter {

      @Advice.OnMethodExit(onThrowable = Throwable.class)
      public static void exit(@Advice.Origin String methodName) {
        System.out.println("Now exiting: \n"+methodName);
      }
  }
}
Bu kodu agent olarak kullanılabilecek bir jar haline getirelim
javac -cp byte-buddy-1.10.22.jar;. SimpleInstru.java
jar cfm simpleInstrumentation.jar instru.mf
SimpleInstru.class SimpleInstru\$TimeFooter.class
Agent olması için instru.mf dosyası şöyle olmalı
Premain-Class: SimpleInstru
Class-Path: byte-buddy-1.10.22.jar
Daha sonra kendi kodumuzu çalıştırmak için şöyle yaparız
java -javaagent:simpleInstrumentation.jar -jar simpleApplication.jar

Hiç yorum yok:

Yorum Gönder