Byte Buddy官方教程(四) — 注解

此翻译已经合并到Byte Buddy官网,请去官网阅读最新版的文档。
https://bytebuddy.net/#/tutorial-cn

我们刚刚学习了Byte Buddy如果依赖注解提供一些功能。目前为止,Byte Buddy不是唯一一个基于注解API的Java应用。为了在这样的应用中集成动态创建的类型,Byte Buddy允许为它创建的类和成员定义注解。在研究将注解分配给动态创建的类之前,我们看一下给一个运行时类添加注解的示例:

@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeDefinition { }
 
class RuntimeDefinitionImpl implements RuntimeDefinition {
  @Override
  public Class<? extends Annotation> annotationType() {
    return RuntimeDefinition.class;
  }
}
 
new ByteBuddy()
  .subclass(Object.class)
  .annotateType(new RuntimeDefinitionImpl())
  .make();

就像Java的@interface关键字所暗示的,注解在内部代表的是接口类型。因此,注解可以像普通的接口一样被实现。实现接口的唯一不同就是注解的隐式annotationType方法,它决定类表示的注解类型。后一种方法通常返回实现的注解类型的类字面量。除此之外,任何注解属性会被实现,就像是一个接口方法一样。然而,注意,一个注解的默认值需要通过注解方法的实现被重复。

当一个类应该作为另一个类的子类代理时,为动态创建的类定义注解将非常重要。子类代理通常被用于实现cross-cutting concerns(横切关注点),其中子类应该尽可能透明地模仿源类。然而,一个类上的注解不会为它的子类保留,只要这个行为通过定义为一个@Inherited注解被显式要求。用Byte Buddy,通过调用Byte Buddy领域特定语言的(attribute)属性方法,创建返回它的基类注解的子类代理很容易。这个方法要求一个TypeAttributeAppender作为参数。类型属性追加器提供了一种灵活的方式定义基于其基类动态创建的类的注解。例如,通过传递一个TypeAttributeAppender.ForSuperType,一个类的注解会被复制到它动态创建的子类中。注意,注解和类属性追加器是附加的,任何类都不能多次定义注解类型。

被定义的方法和字段注解类似于我们刚讨论过的类型注解。一个方法注解可以被定义为Byte Buddy领域特定语言中用于实现方法的结论性表达式。同样地,字段可以在定义之后添加注解。让我们再一次看个示例:

new ByteBuddy()
  .subclass(Object.class)
    .annotateType(new RuntimeDefinitionImpl())
  .method(named("toString"))
    .intercept(SuperMethodCall.INSTANCE)
    .annotateMethod(new RuntimeDefinitionImpl())
  .defineField("foo", Object.class)
    .annotateField(new RuntimeDefinitionImpl())

上面的代码示例覆写了toString()方法并且用RuntimeDefinition注解了这个覆写的方法。此外,该创建的类定义了字段foo,它带有相同的注解,并且在创建的类本身上定义了后面的注解。

默认情况下,Byte Buddy配置对于动态创建的类或类成员不会预定义任何注解。但是,可以通过提供一个默认的TypeAttributeAppenderMethodAttributeAppender或者FieldAttributeAppender来改变这个行为。注意,这样的默认追加器不是附加的,而是替换它们之前的值。

有时,在定义一个定时,最好不要加载注解类型或其它任何属性的类型。为此,可以使用AnnotationDescription.Builder提供流式接口来定义注解而不触发类的加载,但这是以类型安全为代价的。然而,所有注解属性都是在运行时评估的。

默认情况下,Byte Buddy将注解的任何属性都包含到类文件里,包括通过(default)默认值隐式指定的默认属性。但是,可以通过为ByteBuddy实例提供一个AnnotationFilter来自定义这个行为。

类型注解

Byte Buddy暴露并写入类型注解,因为它们是作为Java 8的一部分被引入的。类型注解作为被声明的注解可以通过任何TypeDescription.Generic实例被访问。如果一个类型注解应该被加到一个泛型类型的字段或方法上,这个被注解的类就可以用TypeDescription.Generic.Builder生成。

属性追加器

Java类文件可以包含任何自定义信息作为所谓的属性。对于一个类型,字段或方法,用Byte Buddy通过使用*AttributeAppender,这样的属性可以被包含。然而,属性追加器也可以用来基于通过拦截的类型,字段或方法提供的信息来定义方法。例如,当覆写子类中的方法时,可以复制拦截方法的所有注解:

class AnnotatedMethod {
  @SomeAnnotation
  void bar() { }
}
new ByteBuddy()
  .subclass(AnnotatedMethod.class)
  .method(named("bar"))
  .intercept(StubMethod.INSTANCE)
  .attribute(MethodAttributeAppender.ForInstrumentedMethod.INSTANCE)

上面的代码覆写AnnotatedMethod类的bar方法,但是复制了被覆盖方法的所有注解,包含参数或类型上的注解。

当一个类被重定义或变基时,相同的规则可能不适用。默认情况下,ByteBuddy被配置为保留变基或重定义方法的任何注解,即使这个方法像上面一样被拦截。但是,通过设置AnnotationRetention策略为DISABLED,这个行为可以被改变,以便丢弃任何预先存在的注解。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值