如何查看Bytecode spring框架生成的代理类?

Spring AOP / ASM库中是否存在API,可让我们读取Spring Generated Proxy类的字节码表示形式。 在我的测试代码中,我可以访问类文件。

private static void printClassBytes(String classFilePath) throws Exception{
    TraceclassVisitor visitor = new TraceclassVisitor(new PrintWriter(System.out));
    ClassReader reader = new ClassReader(new FileInputStream(new File("/xxx/asm_source/asmtest-0.0.1-snAPSHOT/com/test/asm/Application.class")));
    
    reader.accept(visitor,0);
}

但是在我的应用程序中,Proxy类是在运行时使用Spring Integration Gateway生成的,我只有Proxy Object的对象引用。 Spring或ASM中是否有一些API,可以让我使用对象引用来找到相应Proxy类的字节码 像

private static void printClassBytes(Object obj) throws Exception{
iCMS 回答:如何查看Bytecode spring框架生成的代理类?

我不知道Spring是否具有执行此操作的手段,但是AFAIK嵌入在Spring中的ASM类不包含TraceClassVisitor。因此,如果您喜欢它的输出,则必须直接使用ASM(工件asm-util),我假设您是为示例代码使用的。如果您想坚持使用板载工具,则只需编写一个转换器,即可将全字节代码作为类文件转储到文件中,然后使用JDK命令行工具javap查看该文件,例如通过javap -c -p -v MyDumpedBytes.class

无论如何,一件容易的事是实现Java代理,并通过-javaagent:/path/to/my-agent.jar将其附加到Java命令行,以启动Spring项目。我为您找到了this article,它说明了如何使用清单文件等实现简单的Java代理,以及如何通过Java Attach API将其附加到正在运行的进程。本文以Javassist为例,编写了一个转换器,但您可以改用ASM。

您的Java代理+转换器看起来像这样:

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;

import java.io.PrintWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

class TraceClassTransformer implements ClassFileTransformer {

  /**
   * Attach agent dynamically after JVM start-up
   */
  public static void agentmain(String commandLineOptions,Instrumentation instr) {
    premain(commandLineOptions,instr);
  }

  /**
   * Start agent via <code>-javaagent:/path/to/my-agent.jar=<i>options</i></code> JVM parameter
   */
  public static void premain(String commandLineOptions,Instrumentation instrumentation) {
    TraceClassTransformer transformer = new TraceClassTransformer();
    instrumentation.addTransformer(transformer,true);
  }

  @Override
  public byte[] transform(ClassLoader loader,String className,Class<?> classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer) throws IllegalClassFormatException {
    dumpClass(classfileBuffer);
    // Do not apply any transformation
    return null;
  }

  private void dumpClass(byte[] classfileBuffer) {
    TraceClassVisitor visitor = new TraceClassVisitor(new PrintWriter(System.out));
    ClassReader reader = new ClassReader(classfileBuffer);
    reader.accept(visitor,0);
  }

}

只需确保代理的清单通过Can-Retransform-Classes: true启用重新转换即可。

代理启动后,您可以致电instrumentation.retransformClasses(proxyInstance.getClass());,然后享受日志输出。

为了使本示例更简单,让我们使用byte-buddy-agent,它包含一个精巧的小工具集,用于在运行时附加转换器,而无需将它们包装到Java代理中。该构件很小,不包含其余的ByteBuddy,仅包含代理工具。

这将简化您的类(您可以保留或删除premainagentmain方法,具体取决于您是否打算将该类用作Java代理):

import net.bytebuddy.agent.ByteBuddyAgent;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;

import java.io.Closeable;
import java.io.PrintWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Proxy;
import java.security.ProtectionDomain;

class TraceClassTransformer implements ClassFileTransformer {
  public static void main(String[] args) throws UnmodifiableClassException {
    // Easy way to get an Instrumentation instance,so we can directly register our transformer on it
    Instrumentation instrumentation = ByteBuddyAgent.install();
    // I am just creating a Java dynamic proxy for a JRE interface. In your own application,// you would just get a reference to a dynamic proxy created by Spring.
    Object proxyInstance = Proxy.newProxyInstance(
      Closeable.class.getClassLoader(),new Class<?>[] { Closeable.class },(proxy,method,args1) -> null
    );

    // Register + use dummy ClassFileTransformer,then unregister again (optional)
    TraceClassTransformer transformer = new TraceClassTransformer();
    try {
      instrumentation.addTransformer(transformer,true);
      instrumentation.retransformClasses(proxyInstance.getClass());
    }
    finally {
      instrumentation.removeTransformer(transformer);
    }
  }

  @Override
  public byte[] transform(ClassLoader loader,0);
  }
}

运行示例main类时,您将获得类似以下内容的控制台日志:

// class version 58.0 (58)
// access flags 0x11
public final class com/sun/proxy/$Proxy0 extends java/lang/reflect/Proxy implements java/io/Closeable {


  // access flags 0xA
  private static Ljava/lang/reflect/Method; m0

  // access flags 0xA
  private static Ljava/lang/reflect/Method; m1

  // access flags 0xA
  private static Ljava/lang/reflect/Method; m2

  // access flags 0xA
  private static Ljava/lang/reflect/Method; m3

  // access flags 0x1
  public <init>(Ljava/lang/reflect/InvocationHandler;)V
    ALOAD 0
    ALOAD 1
    INVOKESPECIAL java/lang/reflect/Proxy.<init> (Ljava/lang/reflect/InvocationHandler;)V
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 2

(...)
本文链接:https://www.f2er.com/2009966.html

大家都在问