JAVA基礎5--注解的實現原理


一、注解簡介

注解也叫元數據,是JDK1.5版本開始引入的一個特性,用於對代碼進行標記說明,可以對包、類、接口、字段、方法參數、局部變量等進行注解修飾

1.1、注解的類型

1、JDK注解和框架注解:JDK本身提供了很多注解比如@Resource、@PostConstruct等;另外常用的框架也提供了很多注解,比如Spring的@Autowired,@Service等等,這些注解使用時會自動被JDK或框架進行識別解析;

2、元注解:元注解用於修飾注解的,如@Retention(標明注解被保留的階段)、@Target(標明注解使用的范圍)、@Inherited(標明注解可繼承)、@Documented(標明是否生成javadoc文檔)

3、自定義注解:用戶可以根據自行需求自定義注解

 

1.2、元注解

@Retention:定義注解的生命周期,默認是CLASS,取值范圍如下:

SOURCE 在編譯階段被拋棄,通常用於編譯時使用,比如@Override注解
CLASS 在編譯階段會被寫入字節碼,當類加載的時候會被丟棄
RUNTIME 不會被丟棄,運行期間也可以使用,所以通過反射機制就可以讀取該注解的信息,通常自定義注解都會采用RUNTIME類型

 

@Target:定義注解可以修飾的目標,默認是可以修飾任意目標,取值范圍如下

TYPE 用於描述類、接口或enum聲明,如@Service、@Component等
FIELD 用於描述屬性,比如@JSONField等
METHOD 用於描述方法,比如@Override
PARAMETER 用於描述方法參數,比如Mybatis框架中的@Param
CONSTRUCTOR 用於描述構造函數
LOCAL_VARIABLE 用於描述局部變量
ANNOTATION_TYPE 用於描述注解類型,比如@Target本身,@Retention,@Document注解等
PACKAGE 用於描述包名
TYPE_PARAMETER 用於描述參數類型
TYPE_USE 表示該注解能使用在使用類型的任意語句中

 

@Inherited:定義注解是否繼承給子類

當@Inherited注解修飾了一個注解,那么如果這個注解修飾了一個類,那么這個類的子類也會繼承該注解

@Documented:定義注解是否將注解信息加到Java文檔中

 

1.3、注解的組成

注解通常有幾個部分組成,包括修飾該注解的元注解,注解名稱和注解方法,當然也可以將注解僅當作標記作用,沒有任何方法也行,比如@Override注解就沒有任何方法,僅當作標記使用

二、注解的使用

通常我們Web服務提供接口需要用戶登錄之后才可以訪問,此時如果每個接口都判斷下用戶是否登錄就會冗余很多的代碼,所以需要在執行接口方法之前有一層驗證用戶登錄的邏輯,可以通過過濾器,攔截器等方式實現,此時就可以配合注解來實現,在需要進行登錄驗證的方法上添加一個自定義的注解,然后每個添加了注解的方法就需要驗證登錄,沒有注解的方法就不需要登錄,實現方式如下:

自定義注解@Logined

@Documented
@Target(ElementType.METHOD) /** 修飾方法*/
@Retention(RetentionPolicy.RUNTIME)/** 生命周期為運行期間*/
public @interface Logined {

    /** 定義方法,如果沒有登錄的情況下是否直接拋異常*/
    boolean exception() default false;
}

 

定義了注解之后就可以直接使用,但是想要使注解的效果生效,就需要有一套獲取注解並處理業務的邏輯,此時就離不開Java的反射機制,需要通過反射機制獲取到修飾在方法、類、屬性上的注解來進行判斷是否加了注解。

另外在使用Spring框架時,可以配置AOP來配合使用自定義注解,比如以下案例就是用來處理@Logined注解的邏輯:

@Aspect
@Component
public class LoginAspect {

    @Around("@annotation(com.test.annotation.Logined)") public Object doBefore(ProceedingJoinPoint jp) throws Throwable {
        if (MessageConfig.LOCAL.get() == null) {
            System.out.println("請求用戶為空,返回401:" + jp.getSignature().getName());
            return Result.returnUnauthorized();
        }
        return jp.proceed();
    }
}

 

三、注解的實現原理

注解本身沒有任何邏輯,只能起到標記的作用,實現的邏輯完全取決於處理注解的邏輯,而處理注解就需要先找到注解,此時就離不開Java的反射機制,主要是通過Constructor、Class、Method、Field等反射相關類的getAnnotation(Class annotationClass)方法獲取對應的注解,如果能獲取到注解那么就表示被注解修飾了,案例如下:

 1 /** 1.查找類上的注解 */
 2         Annotation classAnnotation = cla.getAnnotation(Logined.class);
 3         if(classAnnotation != null){
 4             System.out.println("類被@Logined注解修飾");
 5         }
 6 
 7         /** 2.查找方法上的注解 */
 8         Method[] methods = cla.getMethods();
 9         for (Method method : methods){
10             if(method.getAnnotation(Logined.class) != null){
11                 System.out.println("方法:" + method.getName() + "被注解@Logined" + "修飾");
12             }
13         }
14 
15         /** 3.查找屬性上的注解 */
16         Field[] fields = cla.getFields();
17         for (Field field : fields){
18             if(field.getAnnotation(Logined.class) != null){
19                 System.out.println("屬性:" + field + "被注解@Logined" + "修飾");
20             }
21         }
22 
23         /** 4.查找構造函數上的注解 */
24         Constructor constructor = cla.getConstructor(String.class);
25         if(constructor.getAnnotation(Logined.class)!=null){
26             System.out.println("構造器被@Logined注解修飾");
27         }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM