1. 程式人生 > >Java自定義註解Annotation詳解

Java自定義註解Annotation詳解

一:簡介

開發中經常使用到註解,在專案中也偶爾會見到過自定義註解,今天就來探討一下這個註解是什麼鬼,以及註解的應用場景和如何自定義註解。

下面列舉開發中常見的註解

  • @Override:用於標識該方法繼承自超類, 當父類的方法被刪除或修改了,編譯器會提示錯誤資訊(我們最經常看到的toString()方法上總能看到這貨)
  • @Deprecated:表示該類或者該方法已經不推薦使用,已經過期了,如果使用者還是要使用,會生成編譯的警告
  • @SuppressWarnings:用於忽略的編譯器警告資訊

  • Junit測試:@Test

  • Spring的一些註解:@Controller、@RequestMapping、@RequestParam、@ResponseBody、@Service、@Component、@Repository、@Resource、@Autowire
  • Java驗證的註解:@NotNull、@Email

下面看一下註解Override.java的廬山真面目

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {

}

二:註解基本知識

1. 註解資料型別

註解是寫在.java檔案中,使用@interface作為關鍵字, 所以註解也是Java的一種資料型別,從廣泛的定義來說,Class、Interface、Enum、Annotation都屬於Class型別。

2. 元註解

在建立註解的時候,需要使用一些註解來描述自己建立的註解,就是寫在@interface上面的那些註解,這些註解被稱為元註解,如在Override中看到的@Target、@Retention等。下面列出一些元註解

  • @Documented: 用於標記在生成javadoc時是否將註解包含進去,可以看到這個註解和@Override一樣,註解中空空如也,什麼東西都沒有

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Documented {
    
    }
  • @Target:用於定義註解可以在什麼地方使用,預設可以在任何地方使用,也可以指定使用的範圍,開發中將註解用在類上(如@Controller)、欄位上(如@Autowire)、方法上(如@RequestMapping)、方法的引數上(如@RequestParam)等比較常見。

    • TYPE : 類、介面或enum宣告
    • FIELD: 域(屬性)宣告
    • METHOD: 方法宣告
    • PARAMETER: 引數宣告
    • CONSTRUCTOR: 構造方法宣告
    • LOCAL_VARIABLE:區域性變數宣告
    • ANNOTATION_TYPE:註釋型別宣告
    • PACKAGE: 包宣告

    Target.java

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        /**
         * Returns an array of the kinds of elements an annotation type
         * can be applied to.
         * @return an array of the kinds of elements an annotation type
         * can be applied to
         */
        ElementType[] value();
    }
    public enum ElementType {
        /** Class, interface (including annotation type), or enum declaration */
        TYPE,
    
        /** Field declaration (includes enum constants) */
        FIELD,
    
        /** Method declaration */
        METHOD,
    
        /** Formal parameter declaration */
        PARAMETER,
    
        /** Constructor declaration */
        CONSTRUCTOR,
    
        /** Local variable declaration */
        LOCAL_VARIABLE,
    
        /** Annotation type declaration */
        ANNOTATION_TYPE,
    
        /** Package declaration */
        PACKAGE,
    
        /** Type parameter declaration */
        TYPE_PARAMETER,
    
        /** Use of a type */
        TYPE_USE
    }
  • @Inherited:允許子類繼承父類中的註解,可以通過反射獲取到父類的註解

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    
    }
  • @Constraint:用於校驗屬性值是否合法

    @Documented
    @Target({ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Constraint {
        Class<? extends ConstraintValidator<?, ?>>[] validatedBy();
    }
  • @Retention:註解的宣告週期,用於定義註解的存活階段,可以存活在原始碼級別、編譯級別(位元組碼級別)、執行時級別

    • SOURCE:原始碼級別,註解只存在原始碼中,一般用於和編譯器互動,用於檢測程式碼。如@Override, @SuppressWarings。
    • CLASS:位元組碼級別,註解存在於原始碼和位元組碼檔案中,主要用於編譯時生成額外的檔案,如XML,Java檔案等,但執行時無法獲得。 如mybatis生成實體和對映檔案,這個級別需要新增JVM載入時候的代理(javaagent),使用代理來動態修改位元組碼檔案。
    • RUNTIME:執行時級別,註解存在於原始碼、位元組碼、java虛擬機器中,主要用於執行時,可以使用反射獲取相關的資訊。

      @Documented
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.ANNOTATION_TYPE)
      public @interface Retention {
          /**
           * Returns the retention policy.
           * @return the retention policy
           */
          RetentionPolicy value();
      }

3. 註解的內容

在上面的註解原始碼中可以看到有的註解中沒有任何內容,有的註解的有內容,看似像方法。

註解的內容的語法格式: 資料型別 屬性名() default 預設值,資料型別用於描述屬性的資料型別,預設值是說當沒有給屬性賦值時使用預設值,一般String使用空字串”“作為預設值,陣列一般使用空陣列{ }作為預設值.

下面看一下SpringMVC中的RequestMapping的註解的宣告

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};
    String[] params() default {};
    String[] headers() default {};
    String[] consumes() default {};
    String[] produces() default {};
}

使用SpringMVC中的RequestMapping註解

@RequestMapping(value = "/list", 
                method = RequestMethod.POST, 
                produces = {"application/json;charset=UTF-8;"})
public String list(){

}

4. 註解的使用場景

可以通過註解的宣告週期來分析註解的使用場景:

  • SOURCE原始碼級別:給編譯器使用,如@Override、@Deprecated 等, 這部分開發者應該使用的場景不多
  • CLASS:位元組碼級別,這部分也很少見到
  • RUNTIME:執行時級別,這個是最多的,幾乎開發者使用到的註解都是執行時級別,執行時註解常用的有以下幾種情況
    • 註解中沒有任何屬性的,空的註解,這部分註解通常起到一個標註的作用,如@Test、@Before、@After,通過獲取這些標記註解在邏輯上做一些特殊的處理
    • 可以使用約束註解@Constraint來對屬性值進行校驗,如@Email, @NotNull等
    • 可以通過在註解中使用屬性來配置一些引數,然後可以使用反射獲取這些引數,這些註解沒有其他特殊的功能,只是簡單的代替xml配置的方式來配置一些引數。使用註解來配置引數這在Spring boot中得到了熱捧,如@Configuration

關於配置方式xml vs annotation, 一般使用xml配置一些和業務關係不太緊密的配置,使用註解配置一些和業務密切相關的引數。

三:註解和反射基本API

// 獲取某個型別的註解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass);
// 獲取所有註解(包括父類中被Inherited修飾的註解)
public Annotation[] getAnnotations(); 
// 獲取宣告的註解(但是不包括父類中被Inherited修飾的註解)
public Annotation[] getDeclaredAnnotations();
// 判斷某個物件上是否被某個註解進行標註
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

// 獲取某個類宣告的所有欄位
public Field[] getDeclaredFields() throws SecurityException;
// 獲取某個方法
public Method getMethod(String name, Class<?>... parameterTypes);

四:自定義註解

使用自定義註解+攔截器或者是AOP等可以進行許可權的控制。

下面通過定義一個註解用來限制當用戶訪問介面時必須要登入的示例

步驟一:定義註解
RequiresLogin.java

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresLogin {

}

步驟二:使用註解

@Controller
@RequestMapping("/user")
public class UserController {
    @RequiresLogin
    @RequestMapping(value = "/list", produces = {"application/json;charset=UTF-8;"})
    public String getUserList(){

        System.out.println("--------------");
        return "[{'id': 1, 'username':'zhangsan'}]";
    }
}

步驟三:使用AOP進行攔截,解析註解

public class LoginAdvices {
    public void before(JoinPoint joinPoint) throws Exception{

        Object target = joinPoint.getTarget();
        String methodName = joinPoint.getSignature().getName();

        System.out.println(target + "-------" + methodName);
        Method method = target.getClass().getMethod(methodName);
        boolean annotationPresent = method.isAnnotationPresent(RequiresLogin.class);
        if (annotationPresent) {
            // 使用者必須登入
            boolean isLogin = false;
            if (!isLogin) {
                throw new Exception("訪問該介面必須先登入");
            } else {
                System.out.println("已登入...");
            }
        }
    }
}

在applicationContext.xml中配置aop

<bean id="loginAdvices" class="com.mengdee.manager.aop.LoginAdvices"/>
    <!-- aop配置 -->
    <aop:config proxy-target-class="true">
        <!--切面 -->
        <aop:aspect ref="loginAdvices">
            <!-- 切點 -->
            <aop:pointcut id="pointcut1" expression="execution(* com.mengdee.manager.controller.*.*(..))"/>
            <!--連線通知方法與切點 -->
            <aop:before method="before" pointcut-ref="pointcut1"/>
        </aop:aspect>
    </aop:config>

自定義異常

  • 為什麼要自定義異常
    Java雖然提供了豐富的異常處理類,但是在專案中還會經常使用自定義異常,其主要原因是Java提供的異常類在某些情況下還是不能滿足各種業務的需求。 例如系統中有些錯誤是符合Java語法,但不符合業務邏輯。如當用戶登入時賬號不存在或者賬號已鎖定可以自定義一個賬號異常AccountException。
    或者有些情況下Java的同一個異常可能會有多種原因引起,在排查問題時不容易定位錯誤,此時可以使用自定義一個更加明確的異常。

  • 自定義異常的好處:自定義異常可以使異常更加明確,可以隱藏底層的異常,這樣更安全,異常資訊更加直觀。

  • 自定義異常的使用:自定義異常一般繼承自Exception或者RuntimeException,根據業務需要可以帶一些屬性作為建構函式的引數,自定義異常需要程式設計師手動丟擲異常,並處理異常。

  • 下面是Apache Shiro中自定義異常的示例

public class ShiroException extends RuntimeException {
    public ShiroException() {
    }

    public ShiroException(String message) {
        super(message);
    }

    public ShiroException(Throwable cause) {
        super(cause);
    }

    public ShiroException(String message, Throwable cause) {
        super(message, cause);
    }
}

相關推薦

Java定義註解Annotation

一:簡介 開發中經常使用到註解,在專案中也偶爾會見到過自定義註解,今天就來探討一下這個註解是什麼鬼,以及註解的應用場景和如何自定義註解。 下面列舉開發中常見的註解 @Override:用於標識該方法繼承自超類, 當父類的方法被刪除或修改了,編譯器會提示錯

Java 基礎之--註解Annotation

註解 java 基礎 time span face 自定義註解 div ace rtu 自定義註解入門: public @interface Annotation01 { //set default value ""; String value() de

java定義註解學習(二)_註解

上篇文章,我們簡單的實現了一個自定義註解,相信大家對自定義註解有了個簡單的認識,這篇,這樣介紹下註解中的元註解和內值註解 整體圖示 內建註解 @Override 重寫覆蓋 這個註解大家應該經常用到,主要在子類重寫父類的方法,比如toString()方法 package com.kevin.demo;

Java Web定義MVC框架

分享一個大神的人工智慧教程!http://blog.csdn.net/jiangjunshow 最近給學生講Java Web,希望他們能夠在學完這部分內容後自己實現一個MVC框架。但是突然發現百度上能搜尋到的靠譜的資料並不是很多,有些只是原理沒有程式碼實現,有些有程式碼實現但是

Java定義註解之元註解(meta-annotation)Target、Retention、Documented、Inherited介紹

元註解:   元註解的作用就是負責註解其他(如:自定義)註解,用來對其它 annotation型別作說明。Java定義了4個標準的meta-annotation型別:    [email protected]    [email protected

JAVA 與 MyCat(5) 類的載入 Java內省/反射機制 註解Annotation

通過mycat來學習java了^^。 上一篇瞭解了XML解析的四種方式,並對MyCat的原始碼進行了修改,這一篇接著往下看: dtd = XMLRuleLoader.class.getResourceAsStream(dtdFile); x

杜鵬的個人部落格 Flex使用Blazeds與Java互動及定義物件轉換

一、建立Flex與Java互動的工程。   本文中講到的互動是利用Blazeds的,因為這個是免費的,呵呵,我是窮人。   首先就是去下載Blazeds的壓縮包,這個可以從官網或者CSDN、JavaEye上下到。解壓縮這個包,將裡面的Blazeds.war解壓,後面建立工程時要使用。   在MyEclips

Java定義註解反射校驗數據

sda new out 格式 是否 本地 imp 使用範圍 數據類型 package com.annotations.ecargo; import java.lang.annotation.ElementType; import java.lang.annotati

java定義註解

不包含 doc 1.2 color 子類 局部變量 ati 包含 ant Java註解是附加在代碼中的一些元信息,用於一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。註解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annot

定義控件(七):drawText()

字體 相對 awt 除了 4條 nbsp pan ase span 比較基礎的一個方法。即繪制文本 使用如下: Paint paint = new Paint(); paint.setColor(Color.RED); // 紅色字體 paint.setS

Java中的註解

oca 目的 它的 解包 log 重寫 XML variable ted 詳解Java中的註解 在Java中,註解(Annotation)引入始於Java5,用來描述Java代碼的元信息,通常情況下註解不會直接影響代碼的執行,盡管有些註解可以用來做到影響代碼執行。 註解

定義轉場(一)

assign pda 好的 led hint ext hid case delegate 前言 本文是我學習了onevcat的這篇轉場入門做的一點筆記。 今天我們來實現一個簡單的自定義轉場,我們先來看看這篇文章將要實現的一個效果圖吧: 過程詳解 熱身準備 我們先創建一

java 定義註解

tar 基本用法 而且 最簡 ida outline plain 現在 傳播 參考鏈接:https://blog.csdn.net/hbzyaxiu520/article/details/6212969 JAVA自定義註釋(Target,Retention,Document

Java 定義註解&通過反射獲取類、方法、屬性上的註解

反射 JAVA中的反射是執行中的程式檢查自己和軟體執行環境的能力,它可以根據它發現的進行改變。通俗的講就是反射可以在執行時根據指定的類名獲得類的資訊。   註解的定義 註解通過 @interface 關鍵字進行定義。 /** * 自定義註解 *

pyhanlp 停用詞與使用者定義詞典功能

hanlp的詞典模式 之前我們看了hanlp的詞性標註,現在我們就要使用自定義詞典與停用詞功能了,首先關於HanLP的詞性標註方式具體請看HanLP詞性標註集。 其核心詞典形式如下: 自定義詞典 自定義詞典有多種新增模式,首先是展示的一個小例子,展示了詞彙的動態增加與強行插入,

java定義註解2】java定義註解結合Spring AOP

      承接上一篇,註解應用於屬性,本篇定義了一個用於方法的註解,結合Spring AOP 實現 切面程式設計。       以下demo演示使用了SpringBoot,與SSM中使用方式大致相同,效果如下: 1、自定義註解(用

java定義註解1】java定義註解-屬性

        關於自定義註解,以前專案種應用的不多,最近看新專案過程中發現了挺多自定義註解相關內容,使用起來比較巧妙,於是 總結了兩種方式,記錄如下:         第一種:結合反射進行屬性注入,程式碼如下:

JVM堆記憶體管理與定義分配引數

堆記憶體模型:   在Java中,堆被劃分成兩個不同的區域:新生代(Young),老年代(Old)。而Permanent屬於永久代(方法區),不屬於堆記憶體。新生代又被分為了三個區域:Eden,from  survivor,to survivor。這樣劃分的目的

java 定義註解驗證 (僅限於實體屬性值上的註解

資源下載地址:http://download.csdn.net/detail/weilai_zhilu/9761533   該驗證主要包含三部分 註解驗證類 註解處理方法類 實體類 測試類 第一部分:註解驗證類(此部分暫時只寫了三個驗證類) 下面

java定義註解解析及相關場景實現

註解(Annotation)是java1.5之後提供的一種語法。其主要作用是編譯檢查(比如@override)和程式碼分析(通過程式碼中添加註解,利用註解解析器對添加了註解的程式碼進行分析,獲取想要的結果,一般自定義的註解都是這一種功能)。 1.1 JDK提供的註解 JDK提供的