Java自定义注解的实现

Java 自定义注解的实现

简介

注解:说明程序的,给计算机看的。

注释:用文字描述程序的,给程序员看的。

定义:注解(Annotation),也叫元数据,一种代码级别的说明,它是 JDK1.5 以后版本引入的一个特性,与类、接口、枚举在同一个层次。可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

概念描述:

  • JDK1.5 之后的新特性
  • 用于说明程序
  • 使用注解:@注解名称

作用分类:

  • 编写文档:通过代码里标识的注解生成文档
  • 代码分析:通过注解对代码进行分析(利用反射)
  • 编译检查:通过代码里的注解让编译器能够实现基本的编译检查例如 Override

JDK 中预定义的一些注解

  • @Override:检测被该注解标注的方法是否是继承自夫类 / 接口的
  • @Deprecated:表示该注解标注的内容,已过时
  • @SuppressWarnings:压制警告

自定义注解

注解的定义规则

观察预定义注解的源码

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

可以看出,注解的定义方法是

@元注解
@元注解
....
public @interface 注解名{

}

其中,元注解可以省略,元注解的概念,我们下面再说。

注解的本质

模仿上面定义的方式,创建一个自定义注解

public @interface MyAnno{

}

使用javac命令编译,查看源码:

public interface MyAnno extends java.lang.annotation.Annotation{}

所以注解本质上就是一个接口,其默认继承了 Annotation 接口

注解中的属性

注解本质就是一个接口,所以属性本质上就是接口中可以定义的成员方法。

接口里面能定义的,注解内都可以定义

属性返回值的要求:

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以上的数据类型
  • 不能是 void 或者包装类型

下面是定义一个包含属性的注解的声明:

package cn.rayfoo.common.annotation.validate;

/**

  • @author rayfoo@qq.com

  • @version 1.0

  • <p></p>

  • @date 2020/8/7 11:19
    */
    public @interface NotNull {

    int myProp1();

    String myProp2();

    long[] myProp3();

}

此时,在使用注解的时候,必须给属性赋值

属性的修饰default

使用注解时,不需要给注解赋值,可以在属性后加 default 修饰。不加修饰的为必须指定的内容。

package cn.rayfoo.common.annotation.validate;

/**

  • @author rayfoo@qq.com

  • @version 1.0

  • <p></p>

  • @date 2020/8/7 11:19
    */
    public @interface NotNull {

    int myProp1() default 10;

    String myProp2() default "rayfoo";

    long[] value();

}

使用带有参数的注解

数字属性使用 {} 修饰

@NotNull(prop2 = "giao",value={1L,2L})

如果有且只有一个必须赋值的属性,并且属性名为 value,属性的 name 可以省略

@NotNull(value={1L,2L})

数组中如果只有一个元素,大括号可以省略

@NotNull(value=1L})

带有注解类型属性的使用方式

    @ApiImplicitParams({@ApiImplicitParam(name = "name", value = "用户名", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "phoneNumber", value = "手机号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "signature", value = "签名", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "email", value = "邮箱", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "code", value = "验证码", required = true, dataType = "String", paramType = "query"),
    })

包含枚举属性的注解使用方式

@RequestMapping(value = "/user",method = HttpMethod.DELETE)

元注解

元注解就是用于描述注解的注解

@Target:描述注解能够作用的位置

下面时 target 的源码,其只有一个枚举类数组类型的属性 ElementType[]

@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();
}

ElementType取值

public enum ElementType {
    /** 类和接口上 */
    TYPE,
<span class="hljs-comment">/** 字段上 */</span>
FIELD,

<span class="hljs-comment">/** 方法上 */</span>
METHOD,

<span class="hljs-comment">/** 参数上 */</span>
PARAMETER,

<span class="hljs-comment">/** 构造上 */</span>
CONSTRUCTOR,

<span class="hljs-comment">/** 本地变量上 */</span>
LOCAL_VARIABLE,

<span class="hljs-comment">/** 注解上 */</span>
ANNOTATION_TYPE,

<span class="hljs-comment">/** 包上 */</span>
PACKAGE,

<span class="hljs-comment">/**
 * 类型参数上
 *
 * <span class="hljs-doctag">@since</span> 1.8
 */</span>
TYPE_PARAMETER,

<span class="hljs-comment">/**
 * Use of a type
 *
 * <span class="hljs-doctag">@since</span> 1.8
 */</span>
TYPE_USE

}

这个可以根据自己的需要,添加合适的修饰。

@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 {
    /**
     * 注解只保留在源文件,当 Java 文件编译成 class 文件的时候,注解被遗弃;
     */
    SOURCE,
<span class="hljs-comment">/**
 * 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
 */</span>
CLASS,

<span class="hljs-comment">/**
 * 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;(自定义注解一般都用RUNTIME)
 */</span>
RUNTIME

}

@Retention:描述注解能够保留的阶段

@Documented:描述注解是否能被抽取到 API 文档中

加上该注解后,其修饰的注解会被抽取到JavaDoc文档中

@Inherited:描述注解是否可以被子类继承

加入此注解后继承了加了此注解修饰的类的子类,也会自动加上该注解修饰的注解

注解的扫描

加入注解后,对类没有任何的影响,真正进行操作的是读取注解处,我们可以借助反射中的知识,读取并借助注解的属性进行一些操作。一般配合 AOP 一起使用。

field.isAnnotationPresent(注解.class)
注解 verify = field.getAnnotation(注解.class);
String name = 注解.name();
...判断

__EOF__

  • 本文作者: 张瑞丰
  • 本文链接: https://www.cnblogs.com/zhangruifeng/p/13454114.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。