使用自定义注解和切面AOP实现Java程序增强

1.注解介绍 1.1注解的本质

Oracle官方对注解的定义为:

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.

注解是元数据的一种形式,它提供有关程序的数据,该数据不属于程序本身。 注解对其注释的代码操作没有直接影响。

而在JDK的Annotation接口中有一行注释如此写到:

/** * The common interface extended by all annotation types. * ... */ public interface Annotation {...}

这说明其他注解都扩展自 Annotation 这个接口,也就是说注解的本质就是一个接口。
以 Spring Boot 中的一个注解为例:

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface Component { String value() default ""; }

它实际上相当于:

public interface Component extends Annotation{...}

而@interface 可以看成是一个语法糖。

1.2注解的要素

依然来看 @Component 这个例子:

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface Component { String value() default ""; }

在注解定义上有几个注解@Target, @Retention, @Documented,被称为 元注解

所谓元注解就是说明注解的注解

Java 中的元注解共有以下几个:

1.2.1 @Target

@Target顾名思义,这个注解标识了被修饰注解的作用对象。我们看看它的源码:

@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }

可以看到,这个注解的 value 值是一个数组,这也就意味着注解的作用对象可以有多个。 其取值范围都在ElementType这个枚举之中:

public enum ElementType { /** 类、接口、枚举定义 */ TYPE, /** 字段,包括枚举值 */ FIELD, /** 方法 */ METHOD, /** 参数 */ PARAMETER, /** 构造方法 */ CONSTRUCTOR, /** 局部变量 */ LOCAL_VARIABLE, /** 元注解 */ ANNOTATION_TYPE, /** 包定义 */ PACKAGE... }

不同的值代表被注解可修饰的范围,例如TYPE只能修饰类、接口和枚举定义。这其中有个很特殊的值叫做 ANNOTATION_TYPE, 是专门表示元注解的。

在回过头来看 @Component 这个例子, Target 取值为 TYPE。熟悉 Spring Boot 的同学也一定知道,@Component 确实是不能放到方法或者属性前面的。

1.2.2@Retention

@Retention 注解指定了被修饰的注解的生命周期。定义如下:

@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }

可以看到这个注解带一个 RetentionPolicy 的枚举值:

public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }

SOURCE 表示注解编译时可见,编译完后就被丢弃。这种注解一般用于在编译器做一些事情;

CLASS 表示在编译完后写入 class 文件,但在类加载后被丢弃。这种注解一般用于在类加载阶段做一些事情;

RUNTIME 则表示注解会一直起作用。

1.2.3 @Documented

这个注解比较简单,表示是否添加到 java doc 中。

1.2.4 @Inherited

这个也比较简单,表示注解是否被继承。这个注解不是很常用。

注意:元注解只在定义注解时被使用

1.3 注解的构成

从上面的元注解可以了解到,一个注解可以关联多个 ElementType,但只能有一个 RetentionPolicy:

注解的构成

Java 中有三个常用的内置注解,其实相信大家都用过或者见过。不过在了解了注解的真实面貌以后,不妨重新认识一下吧!

1.4 Java内置注解 1.4.1 @Override

@Override它的定义为:

@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }

可见这个注解没有任何取值,只能修饰方法,而且RetentionPolicy 为 SOURCE,说明这是一个仅在编译阶段起作用的注解。

它的真实作用想必大家一定知道,就是在编译阶段,如果一个类的方法被 @Override 修饰,编译器会在其父类中查找是否有同签名函数,如果没有则编译报错。可见这确实是一个除了在编译阶段就没什么用的注解。

1.4.2 @Deprecated

@Deprecated它的定义为:

@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspzgd.html