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         }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章