一文读懂Annotation

点击上方老周聊架构关注我
一、什么是注解
@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)@Documentedpublic @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)@Documentedpublic @interface PrintLog {}
public class PrintLogAspect {(value = "@annotation(com.riemann.core.annotation.PrintLog)")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后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

点个在看你最好看

