@Annotation
使用public @interface xxx{}可以自定义一个注解,在注解上面定义的注解叫做元注解。
以下代码取自开源API文档生成项目Swagger:
@Target({TYPE, PACKAGE, ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface OpenAPIDefinition {
Info info() default @Info;
Tag[] tags() default {};
Server[] servers() default {};
SecurityRequirement[] security() default {};
ExternalDocumentation externalDocs() default @ExternalDocumentation;
Extension[] extensions() default {};
}
使用元注解
在注解中也可以使用注解,我们称这些注解为元注解,上面代码中使用了一些比较常见的元注解。
@Target
@Target({ElementType.TYPE})用于定义注解的使用范围,常见的包含
TYPE:类、接口、枚举
FIELD:字段声明
METHOD:方法声明
PARAMTER:参数声明
CONSTRUACTOR:构造函数声明
LOCAL_VARIABLE:局部变量声明
ANNOTATION_TYPE:其他注解声明
PACKAGE:包声明(代码中的第一行 声明package的时候)
@Retention
@Retention({RetentionPolicy.Runtime})用于定义注释的保留时间,即SOURCE(编译时被忽略)、CLASS(默认的,编译时保留,运行时JVM不保留),RUNTIME(运行时保留,可以反读)
@Inherited
子类可以继承父类的该注解
@Documented
注释文档化
定义注解的属性
注解的属性可以是基本数据类型,也可以是String、Enum、Class、其他Annotation以及他们的数组,注解有一个特殊的属性value,当且仅使用注解并且只定义一个calue值时,可以省略属性名,譬如RequestMapping("xxx"),注解的属性要么是默认值,要么在使用的时候定义了值,编译器不允许初始化不赋值也不允许为空,以下是一个基本的注解定义的例子:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @integer AnnotationCase{
public int value();
public String description() default "no description";
}
处理注解
注解不是注释,我们需要通过获取注解从而进行功能的开发。因为注解的特殊性,所以我们只能通过反射获取注解信息。
TestCase
假设我们已经按上面的栗子定义了注解AnnotationCase,现在我们可以在项目中使用它了:
@AnnotationCase(1)
public class Case1{
...
}
现在我们可以通过反射来扫描注解了:
public class Test {
public static void main(String[] args) {
init();
for (Entry<Integer, Class<?>> item : logicInfos.entrySet()) {
System.out.println(item.getValue().getName());
}
}
public static Map<Integer, Class<?>> logicInfos = new HashMap<Integer, Class<?>>();
public static void init() {
// 当前目录的相对目录
String path = Test.class.getResource("").getPath();
// 加载目录下文件class文件
File requestMsgFiles = new File(path);
String[] allMsgInfos = requestMsgFiles.list();
for (String msgInfo : allMsgInfos) {
try {
// 完整路径:/bin/com/xxl/test/Case1.class
String msgPathInfo = path + msgInfo;
// 计算包名
msgPathInfo = msgPathInfo.substring(msgPathInfo.indexOf("bin") + 4, msgPathInfo.lastIndexOf("."));
msgPathInfo = msgPathInfo.replace("/", ".");
// 根据报名反射获得Class,和注解 @Annotation1的type1值
Class<?> msgClazz = Class.forName(msgPathInfo);
AnnotationCase requestMsgType = msgClazz.getAnnotation(AnnotationCase.class);
// 用注解 @Annotation1的type1值作为key,Class作为value,注册到Map中
logicInfos.put(requestMsgType.type1(), msgClazz);
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
}
}
正确使用反射获取注解
首先我们获取注解信息的前提是运行时注解被保留到了代码中,亦即我们需要定义元注解@Retention({RetentionPolicy.Runtime}),首先关于反射基础内容参见造轮子2 灵活运用反射-鱼鱼的博客
//TODO
参考链接:许雪里的博客

