自定义注解

概念:注解就是说明程序的一个标识,给计算机看的

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

定义:也叫作元数据,是一种代码级别的说明。它是 JDK1.5 引入的一个新特性,是一种特殊的接口。它可以声明在类、字段、方法、变量、参数、包等前面,作为一个描述去使用

作用分类:

  • 编写文档:通过代码中标识的注解生成文档(Swagger)
  • 代码分析:通过代码里的注解对代码进行分析(逻辑判断)
  • 编译检查:通过代码里对应的注解让编译器实现基本的编译检查(Override,Deprecated,FunctionalInterface)

JDK 中预定义的一些注解

  • Override:检测该注解标识的方法是否继承自父类
  • Deprecated:标识方法、类、字段等已经过时,后续的版本可能会将其移除
  • SuppressWarnings:压制警告

自定义注解

格式语法如下:

元注解
public @interface 注解名称{
    属性列表
}

本质:注解本质上是一个接口,该接口事实上默认继承自 Annotation 接口

属性

事实上是接口中的抽象方法

  • 如果定义了属性,在使用属性的时候需要给属性赋值
  • 如果只有一个属性需要赋值,并且这个属性名称是 value,则可以省略 value
  • 数组赋值时,需要使用 {} 包起来。如果数组中只有一个元素,则大括号可以省略属性中的返回值类型有下列取值

基本数据类型、String、枚举、注解

元注解

用于描述注解的注解

注解名称 作用
@Target 描述该注解的作用范围
@Retention 描述注解被保留的阶段
@Documented 描述注解是否被抽取到 api 文档中
@Inherited 描述注解是否可以被继承

@Target的ElementType属性取值如下:

  • Type:作用于类
  • METHOD:作用于方法
  • FIELD:作用于字段

@Retention的RetentionPolicy.RUNTIME:代表当前描述的注解,会保留到 class 字节码文件中,并被 jvm 读取到

案例

编写一个缓存注解,该注解用于缓存指定方法的返回值

public final class CacheUtils {

    /**
     * HashMap 是线程不安全的,这里应该用 ConcurrentHashMap
     */
    private static Map<String, Object> cacheMap = new ConcurrentHashMap<>();

    private CacheUtils() {
    }

    /**
     * 执行当前指定对象的指定方法
     *
     * @param obj        对象
     * @param methodName 执行的方法名称
     * @param params     参数
     * @return 方法执行之后的结果
     */
    public static Object invokeMethod(Object obj, String methodName, Object... params) {
        Class<?> objClass = obj.getClass();
        Object result = null;

        try {
            Method method;
            if (params.length > 0) {
                Class<?>[] classArr = new Class[params.length];
                Object[] valueArr = new Object[params.length];
                for (int i = 0; i < params.length; i++) {
                    classArr[i] = params[i].getClass();
                    valueArr[i] = params[i];
                }
                method = objClass.getDeclaredMethod(methodName, classArr);

                // 获取缓存注解
                Cache cacheAnnotation = method.getAnnotation(Cache.class);
                // 先判断注解是否为空
                if (cacheAnnotation != null) {
                    // 方法有参数,以第一个参数为小key。
                    Object paramsKey = params[0];

                    // 获取大key
                    String key = cacheAnnotation.key();

                    // 拼接key
                    String cacheKey = key + "." + paramsKey;

                    // 获取缓存
                    Object cacheValue = cacheMap.get(cacheKey);

                    // 判断缓存是否存在,如果存在,直接返回缓存的值
                    if (cacheValue != null) {
                        return cacheValue;
                    }
                }
                method.setAccessible(true);
                result = method.invoke(obj, valueArr);

                // 方法执行完了,将数据放入到缓存中
                if (cacheAnnotation != null) {

                    // 获取key
                    // 方法有参数,以第一个参数为小key。
                    Object paramsKey = params[0];

                    // 获取大key
                    String key = cacheAnnotation.key();

                    // 拼接key
                    String cacheKey = key + "." + paramsKey;
                    cacheMap.put(cacheKey, result);
                }
            } else {
                method = objClass.getDeclaredMethod(methodName);

                // 获取缓存注解
                Cache cacheAnnotation = method.getAnnotation(Cache.class);

                // 先判断注解是否为空
                if (cacheAnnotation != null) {

                    // 获取大key
                    String key = cacheAnnotation.key();

                    // 获取缓存
                    Object cacheValue = cacheMap.get(key);

                    // 判断缓存是否存在,如果存在,直接返回缓存的值
                    if (cacheValue != null) {
                        return cacheValue;
                    }
                }
                method.setAccessible(true);
                result = method.invoke(obj);

                // 方法执行完了,将数据放入到缓存中
                if (cacheAnnotation != null) {
                    String key = cacheAnnotation.key();
                    cacheMap.put(key, result);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}
posted @ 2020-11-11 09:59  BNTang  阅读(93)  评论(0编辑  收藏  举报