自定义注解及使用

242 阅读5分钟

注解的定义

注解就是用来做标注用:可以在类、字段变量、方法、接口等位置进行一个特殊的标记,为后续做一些诸如:代码生成、数据校验、资源整合等工作做铺垫。注解一旦对代码标注完成,后续我们就可以结合Java强大的反射机制,在运行时动态地获取到注解的标注信息,从而可以执行很多其他逻辑,完成我们想要的自动化工作。

自定义一个注解

比如说我们想要校验一个 Student 类

public class Student {
    private Long id; 
    private String name;
    private String mobile; // 校验手机号码的长度
}

首先定义注解:@Length

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Length {
    int min()// 允许字符串长度的最小值
    int max()// 允许字符串长度的最大值
    String errorMsg() default "输入参数长度过长或过短"// 自定义错误信息
}

说明:

1、注解的定义有点像定义接口 interface,但唯一不同的是前面需要加一个 @符号

2、注解的成员变量只能使用基本类型、 String或者 enum枚举,比如 int可以,但 Integer这种包装类型就不行,需注意

3、像上面 @Target@Retention这种加在注解定义上面的注解,我们称为 “元注解”,元注解就是专门用于给注解添加注解的注解,简单理解,元注解就是天生就有的注解,可直接用于注解的定义上

4、 @Target(xxx) 用来说明该自定义注解可以用在什么位置,比如:

  • ElementType.FIELD:说明自定义的注解可以用于类的变量
  • ElementType.METHOD:说明自定义的注解可以用于类的方法
  • ElementType.TYPE:说明自定义的注解可以用于类本身、接口或 enum类型
  • 等等… 还有很多,如果记不住,建议现用现查

5、 @Retention(xxx) 用来说明你自定义注解的生命周期,比如:

  • @Retention(RetentionPolicy.RUNTIME):表示注解可以一直保留到运行时,因此可以通过反射获取注解信息

  • @Retention(RetentionPolicy.CLASS):表示注解被编译器编译进 class文件,但运行时会忽略

  • @Retention(RetentionPolicy.SOURCE):表示注解仅在源文件中有效,编译时就会被忽略

  • 所以声明周期从长到短分别为:RUNTIME > CLASS > SOURCE ,一般来说,如果需要在运行时去动态获取注解的信息,还是得用RUNTIME,就像本文所用。

获取注解并对其进行验证

public class Verification {
    public static String validate (Object object) throws IllegalAccessException {
        // 首先通过反射获取object对象的类有哪些字段
        Field[] fields = object.getClass().getDeclaredFields();

        // for循环逐个字段校验,看哪个字段上标了注解
        for (Field field : fields) {
            // if判断:检查该字段上有没有标注了@Length注解
            if (field.isAnnotationPresent(Length.class)) {
                // 通过反射获取到该字段上标注的@Length注解的详细信息
                Length length = field.getAnnotation(Length.class);
                field.setAccessible(true); // 让我们在反射时能访问到私有变量
                // 用过反射获取字段的实际值
                int value = ((String) field.get(object)).length();
                // 将字段的实际值和注解上做标示的值进行比对
                if (value < length.min() || value > length.max()) {
                    return length.errorMsg();
                }
            }
        }
        return null;
    }
}

使用注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Length {
    int min()// 允许字符串长度的最小值
    int max()// 允许字符串长度的最大值
    String errorMsg() default "输入参数长度过长或过短"// 自定义错误信息
}

编写测试类

public class Test {
    public static void main(String[] args) {

        Student student = new Student();
        student.setId(1L);
        student.setName("Ning");
        student.setMobile("13012345678");

        try {
            String s = Verification.validate(student);
            if (s == null) {
                System.out.println(student);
            }else {
                throw new RuntimeException(s);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}