为什么AspectJ中生成一个空注释检查?

问题描述 投票:4回答:1

我使用的AspectJ 1.8.8编译时编织,我有这样一个块

@SomeAnnotation(value="someValue")
public List doSomething(String someArg) {
    ...
}

其中@SomeAnnotation与一个“绕”的建议执行。

寻找与JD-GUI字节码,我看到以下生成的代码(略格式化的):

public class SomeClass {
  private static Annotation ajc$anno$5;

  ...

  @SomeAnnotation(value="someValue")
  public List doSomething(String someArg)
  {
    String str = someArg;
    JoinPoint localJoinPoint = Factory.makeJP(ajc$tjp_5, this, this, str);
    Object[] arrayOfObject = new Object[3];
    arrayOfObject[0] = this;
    arrayOfObject[1] = str;
    arrayOfObject[2] = localJoinPoint;
    Annotation tmp56_53 = ajc$anno$5;
    if (tmp56_53 == null) {
      tmp56_53;
    }
    return (List)new SomeClass.AjcClosure11(arrayOfObject).linkClosureAndJoinPoint(69648).around(tmp56_53, (SomeAnnotation)(ajc$anno$5 = SomeClass.class.getDeclaredMethod("doSomething", new Class[] { String.class }).getAnnotation(SomeAnnotation.class)));
  }
}

我想知道为什么条件(if (tmp56_53...))即使存在,因为它似乎什么都不做(并且也是语法不正确的Java?也许是因为这是由浓缩苹果汁产生的?)。我很好奇,是因为它是在一个覆盖工具(JaCoCo)造成“分支未命中”。


Edit 1

这里是javap的原始Java的机器代码:

       0: aload_1
       1: astore_2
       2: getstatic     #480                // Field ajc$tjp_10:Lorg/aspectj/lang/JoinPoint$StaticPart;
       5: aload_0
       6: aload_0
       7: aload_2
       8: invokestatic  #312                // Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
      11: astore_3
      12: invokestatic  #339                // Method com/foo/SomeAspect.aspectOf:()Lcom/foo/SomeAspect;
      15: iconst_3
      16: anewarray     #2                  // class java/lang/Object
      19: astore        4
      21: aload         4
      23: iconst_0
      24: aload_0
      25: aastore
      26: aload         4
      28: iconst_1
      29: aload_2
      30: aastore
      31: aload         4
      33: iconst_2
      34: aload_3
      35: aastore
      36: new           #484                // class com/foo/SomeClass$AjcClosure21
      39: dup
      40: aload         4
      42: invokespecial #485                // Method com/foo/SomeClass$AjcClosure21."<init>":([Ljava/lang/Object;)V
      45: ldc_w         #327                // int 69648
      48: invokevirtual #333                // Method org/aspectj/runtime/internal/AroundClosure.linkClosureAndJoinPoint:(I)Lorg/aspectj/lang/ProceedingJoinPoint;
      51: getstatic     #488                // Field ajc$anno$10:Ljava/lang/annotation/Annotation;
      54: dup
      55: ifnonnull     86
      58: pop
      59: ldc           #75                 // class com/foo/SomeClass
      61: ldc_w         #489                // String someArg
      64: iconst_1
      65: anewarray     #348                // class java/lang/Class
      68: dup
      69: iconst_0
      70: ldc           #171                // class java/lang/String
      72: aastore
      73: invokevirtual #352                // Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
      76: ldc_w         #341                // class com/foo/SomeAnnotation
      79: invokevirtual #358                // Method java/lang/reflect/Method.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
      82: dup
      83: putstatic     #488                // Field ajc$anno$10:Ljava/lang/annotation/Annotation;
      86: nop
      87: checkcast     #341                // class com/foo/SomeAnnotation
      90: invokevirtual #362                // Method com/foo/SomeAspect.around:(Lorg/aspectj/lang/ProceedingJoinPoint;Lcom/foo/SomeAnnotation;)Ljava/lang/Object;
      93: pop
      94: return

貌似ifnonnull可能是有问题的条件,但我不熟悉,在所有JVM指令,我仍然不知道为什么会AspectJ的产生这样的逻辑。

java aop aspectj jvm-bytecode jd-gui
1个回答
1
投票

TL;博士:这是一个正常的延迟初始化,并jd只是困惑。

字节16是它创建new Object[3]

16: anewarray     #2                  // class java/lang/Object

之后,在19-35,它只是立即的局部变量拷贝到堆栈(iconst的指数,aload为参考),然后将它们写入到阵列(aastore)可以看到。眼前的下一个字节是36,这是new运营商(不仅仅是分配,然后紧接着是invokespecial运行构造函数)。

这给我们带来了48字节,这就要求linkClosureAndJoinPoint。你不包括你的常数表,但在45 ldc_w #327加载恒定值69648,这样给我们带来了高达.around点。

现在,一些有趣的事情发生在字节51单链呼叫jd重建现已中断。字节码装入静态注释字段ajc$anno$10(未5,如jd说)压入堆栈。如果注释字段不为空(55),然后执行跳转到86(无操作,作为“着陆点”的跳转),它可完成铸检查((SomeAnnotation)),最后实际上调用了意见。

多数民众赞成跳过的代码(58-82)说这一点,你会从反编译的认识:

SomeClass.class
    .getDeclaredMethod("doSomething", new Class[] { String.class })
    .getAnnotation(SomeAnnotation.class)

然后字节83中的结果存储到静磁场,并且执行从那里进行。

在Java方面,这正是发生了什么:

if (cachedAnnotation == null) {
    cachedAnnotation = getAnnotationOnMethodUsingReflection();
}

AspectJ的字节码是很紧,清洁此处(可能是手工优化,因为这很可能是非常热的代码)。因为这或因为逻辑中断链接的方法调用,jd是感到困惑和分裂空校验和分配无论是。

© www.soinside.com 2019 - 2024. All rights reserved.