1. Repeatable注解的定义
java8以后支持在同一个地方(某个方法或者某个类等)加上相同的注解,前提是要使用@Repeatable
注解,但是在用之前必须知道如何定义一个自定义注解:
自定义注解示例:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Repeatable(ActionUnlockChecks.class)
public @interface ActionUnlockCheck {
int actionType();
}
@Retention
@Retention
注解有一个属性value
,是RetentionPolicy
枚举类型Rentention
搭配RententionPolicy
使用。RetentionPolicy
有3个值:CLASS
RUNTIME
SOURCE
按生命周期来划分可分为3类:
RetentionPolicy.SOURCE
:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
RetentionPolicy.CLASS
:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
RetentionPolicy.RUNTIME
:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
一般要用反射获得注解就要使用RUNTIME
@Target
注解的作用域,属性value
是数组,可以如示例所示填多个作用域,常用的有:TYPE
,METHOD
,PARAMETER
,CONSTRUCTOR
等@Repeatable
属性value
的类型是Class类型,这里创建了一个另一个自定义注解,后面称之为父注解,之前的称之为子注解,示例代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface ActionUnlockChecks {
ActionUnlockCheck[] value();
}
父注解必须有以下特征:
1:作用域必须大于等于子注解
2:父注解的周期要比子注解的周期要小或相同(注意:SOURCE(源码) < CLASS (字节码) < RUNTIME(运行))
3:父注解的value的类型是子注解类型的数组
2. Repeatable注解与反射
java反射是可以得到作用域RUNTIME
的注解的,通过比如java.lang.Class#getAnnotation
方法:
ActionUnlockCheck annotation = joinPoint.getTarget().getClass().getAnnotation(ActionUnlockCheck.class);
但是这就有疑问了:既然注解是可重复的,那这个方法的返回值应该是数组而不是单个?
于是略加研究后发现,当我重复定义了@ActionUnlockCheck
时,其实经过编译后,字节码class内部是这样的:
@ActionUnlockChecks({@ActionUnlockCheck(
actionType = 114
), @ActionUnlockCheck(
actionType = 113
)})
也就是说多个子注解其实会被转换成一个父注解。