造轮子1 注解管理

  created  by  鱼鱼 {{tag}}
创建于 2019年05月14日 19:01:49 最后修改于 2019年05月25日 16:54:02

    @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

参考链接:许雪里的博客

评论区
评论
{{comment.creator}}
{{comment.createTime}} {{comment.index}}楼
评论

造轮子1 注解管理

造轮子1 注解管理

    @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})用于定义注解的使用范围,常见的包含

        @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

参考链接:许雪里的博客


造轮子1 注解管理2019-05-25鱼鱼

{{commentTitle}}

评论   ctrl+Enter 发送评论