一文讀懂Annotation

點擊上方老周聊架構(gòu)關(guān)注我
一、什么是注解
@Document
@Target
@Retention
@Inherited
@Native
@Repeatable
二、元注解
public Documented {}
只能用 public 或默認(default)這兩個修飾訪問權(quán)限。例如 String value(); 這里把方法設(shè)為 defaul 默認類型。
參數(shù)成員只能用【char、byte、short、int、long、float、double、boolean】八種基本數(shù)據(jù)類型和 String、Enum、Class 和 annotations 等數(shù)據(jù)類型,以及這一些類型的數(shù)組。例如 String value(); 這里的參數(shù)成員就為 String。
如果只有一個參數(shù)成員,最好把參數(shù)名稱設(shè)為 “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,/** 方法形式參數(shù)聲明 */PARAMETER,/** 構(gòu)造方法的聲明 */CONSTRUCTOR,/** 局部變量聲明 */LOCAL_VARIABLE,/** 注解類型聲明 */ANNOTATION_TYPE,/** 包的聲明 */PACKAGE,/** 作用于類型參數(shù)(泛型參數(shù))聲明 */TYPE_PARAMETER,/** 作用于使用類型的任意語句(不包括class) */TYPE_USE}
// 可以作用在 構(gòu)造方法、方法、方法形參、屬性、注解類型 上
public Retention {RetentionPolicy value();}
Java 源文件階段
編譯到 class 文件階段
運行期階段
public enum RetentionPolicy {/*** 注解將被編譯器忽略掉*/SOURCE,/*** 注解將被編譯器記錄在class文件中,但在運行時不會被虛擬機保留,這是一個默認的行為*/CLASS,/*** 注解將被編譯器記錄在class文件中,而且在運行時會被虛擬機保留,因此它們能通過反射被讀取到*/RUNTIME}
如果被定義為 RetentionPolicy.SOURCE,則它將被限定在 Java 源文件中,那么這個注解即不會參與編譯也不會在運行期起任何作用,這個注解就和一個注釋是一樣的效果,只能被閱讀 Java 文件的人看到;
如果被定義為 RetentionPolicy.CLASS,則它將被編譯到 Class 文件中,那么編譯器可以在編譯時根據(jù)注解做一些處理動作,但是運行時 JVM(Java虛擬機)會忽略它,并且在運行期也不能讀取到;
如果被定義為 RetentionPolicy.RUNTIME,那么這個注解可以在運行期的加載階段被加載到 Class 對象中。那么在程序運行階段,可以通過反射得到這個注解,并通過判斷是否有這個注解或這個注解中屬性的值,從而執(zhí)行不同的程序代碼段。
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) {// 模擬根據(jù)id查詢用戶名String userName = "公眾號【老周聊架構(gòu)】";return userName;}}
Enter class[Controller] method[findUserNameById] params[{id=666}]End class[Controller] method[findUserNameById]
歡迎大家關(guān)注我的公眾號【老周聊架構(gòu)】,Java后端主流技術(shù)棧的原理、源碼分析、架構(gòu)以及各種互聯(lián)網(wǎng)高并發(fā)、高性能、高可用的解決方案。

點個在看你最好看

