一文读懂Annotation
共 7586字,需浏览 16分钟
·
2021-03-26 20:51
点击上方老周聊架构关注我
一、什么是注解
@Document
@Target
@Retention
@Inherited
@Native
@Repeatable
二、元注解
public Documented {
}
只能用 public 或默认(default)这两个修饰访问权限。例如 String value(); 这里把方法设为 defaul 默认类型。
参数成员只能用【char、byte、short、int、long、float、double、boolean】八种基本数据类型和 String、Enum、Class 和 annotations 等数据类型,以及这一些类型的数组。例如 String value(); 这里的参数成员就为 String。
如果只有一个参数成员,最好把参数名称设为 “value”,后加小括号。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
public Target {
ElementType[] value();
}
public enum ElementType {
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 方法形式参数声明 */
PARAMETER,
/** 构造方法的声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE,
/** 作用于类型参数(泛型参数)声明 */
TYPE_PARAMETER,
/** 作用于使用类型的任意语句(不包括class) */
TYPE_USE
}
// 可以作用在 构造方法、方法、方法形参、属性、注解类型 上
public Retention {
RetentionPolicy value();
}
Java 源文件阶段
编译到 class 文件阶段
运行期阶段
public enum RetentionPolicy {
/**
* 注解将被编译器忽略掉
*/
SOURCE,
/**
* 注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为
*/
CLASS,
/**
* 注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到
*/
RUNTIME
}
如果被定义为 RetentionPolicy.SOURCE,则它将被限定在 Java 源文件中,那么这个注解即不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读 Java 文件的人看到;
如果被定义为 RetentionPolicy.CLASS,则它将被编译到 Class 文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时 JVM(Java虚拟机)会忽略它,并且在运行期也不能读取到;
如果被定义为 RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到 Class 对象中。那么在程序运行阶段,可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。
public Documented {
}
public Inherited {
}
三、如何自定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PrintLog {
}
public class PrintLogAspect {
"@annotation(com.riemann.core.annotation.PrintLog)") (value =
public Object handlerPrintLog(ProceedingJoinPoint joinPoint) throws Throwable {
String clazzName = joinPoint.getSignature().getDeclaringTypeName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
Map<String, Object> nameAndArgs = getFieldsName(this.getClass(), clazzName, methodName, args);
log.info("Enter class[{}] method[{}] params[{}]", clazzName, methodName, nameAndArgs);
Object object = null;
try {
object = joinPoint.proceed();
} catch (Throwable throwable) {
log.error("Process class[{}] method[{}] error", clazzName, methodName, throwable);
}
log.info("End class[{}] method[{}]", clazzName, methodName);
return object;
}
private Map<String, Object> getFieldsName(Class clazz, String clazzName, String methodName, Object[] args) throws NotFoundException {
Map<String, Object > map = new HashMap<>();
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(clazz);
pool.insertClassPath(classPath);
CtClass cc = pool.get(clazzName);
CtMethod cm = cc.getDeclaredMethod(methodName);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
if (attr == null) {
// exception
}
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < cm.getParameterTypes().length; i++) {
map.put( attr.variableName(i + pos), args[i]);
}
return map;
}
}
public class Controller {
public String findUserNameById( int id) {
// 模拟根据id查询用户名
String userName = "公众号【老周聊架构】";
return userName;
}
}
Enter class[Controller] method[findUserNameById] params[{id=666}]
End class[Controller] method[findUserNameById]
欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。
点个在看你最好看