@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
参考链接:许雪里的博客