使用ASM或Javassist改进字段获取和设置性能

ng.*_*ng. 15 java assembly java-bytecode-asm

我想避免在我正在开发的开源项目中反思.在这里,我有类似以下的课程.

public class PurchaseOrder {

   @Property
   private Customer customer;

   @Property
   private String name;
}
Run Code Online (Sandbox Code Playgroud)

我扫描@Property注释以确定我可以设置和反射性地从PurchaseOrder获取.有许多这样的类都使用java.lang.reflect.Field.get()java.lang.reflect.Field.set().

理想情况下,我想为每个属性生成如下调用者.

public interface PropertyAccessor<S, V> {
   public void set(S source, V value);
   public V get(S source);
}
Run Code Online (Sandbox Code Playgroud)

现在,当我扫描类时,我可以创建一个PurchaseOrder类似的静态内部类.

static class customer_Field implements PropertyAccessor<PurchaseOrder, Customer> {
   public void set(PurchaseOrder order, Customer customer) {
      order.customer = customer;
   }  
   public Customer get(PurchaseOrder order) {
      return order.customer;
   }
}
Run Code Online (Sandbox Code Playgroud)

有了这些,我完全避免了反思的代价.我现在可以使用原生性能设置并从我的实例中获取.任何人都可以告诉我如何做到这一点.代码示例会很棒.我在网上搜索了一个很好的例子但是却找不到这样的东西.ASM和Javasist的例子也很差.

这里的关键是我有一个可以传递的界面.所以我可以有各种各样的实现,也许有一个用Java反射作为默认,一个用ASM,一个用Javassist?

任何帮助将不胜感激.

McD*_*ell 10

ASM

使用ASMifierClassVisitor,您可以准确地看到需要编写哪些代码来生成内部类:

ASMifierClassVisitor.main(new String[] { PurchaseOrder.customer_Field.class
    .getName() });
Run Code Online (Sandbox Code Playgroud)

剩下的就是确定在生成器代码中需要参数化的位数.示例输出PurchaseOrder$customer_Field将成为文件inject/PurchaseOrder$customer_Field.class:

public static byte[] dump () throws Exception {

  ClassWriter cw = new ClassWriter(0);
  FieldVisitor fv;
  MethodVisitor mv;
  AnnotationVisitor av0;

  cw.visit(V1_6, ACC_SUPER, "inject/PurchaseOrder$customer_Field",
      "Ljava/lang/Object;"+
      "Linject/PropertyAccessor<Linject/PurchaseOrder;Linject/Customer;>;", 
      "java/lang/Object",
      new String[] { "inject/PropertyAccessor" });
//etc
Run Code Online (Sandbox Code Playgroud)

(我用"注入"作为包.)

您还必须使用ASM的访问者类创建合成访问器:

{
mv = cw.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "access$0", 
          "(Linject/PurchaseOrder;Linject/Customer;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, "inject/PurchaseOrder",
          "customer", "Linject/Customer;");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "access$1", 
          "(Linject/PurchaseOrder;)Linject/Customer;", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "inject/PurchaseOrder", "
          customer", "Linject/Customer;");
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
Run Code Online (Sandbox Code Playgroud)

有关如何注入方法的示例,请参阅此项目.


有了这些,我完全避免了反思的代价.

因为这一切都将在运行时完成:

  • 这种解析和代码生成有一个前期成本
  • 你需要以某种方式发现和反省这些生成的类型