自定义注解
概念:注解就是说明程序的一个标识,给计算机看的
注释:用文字描述程序,给程序员看的
定义:也叫作元数据,是一种代码级别的说明。它是 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;
}
}