Spring原始碼系列:註解說明

glmapper發表於2019-03-02

因為要看Spring中註解的具體定義,所以在說之前,先來簡單說下JAVA中註解的一些基本知識。

元註解

什麼是元註解呢,就是註解的註解。java中提供了以下幾種:

  • @Target

    註解的作用域描述

    public enum ElementType {
        /** 類, 介面 或者列舉 */
        TYPE,
        /** 欄位 */
        FIELD,
        /** 方法 */
        METHOD,
        /** 引數 */
        PARAMETER,
        /** 構造方法 */
        CONSTRUCTOR,
        /** 區域性變數 */
        LOCAL_VARIABLE,
        /** 註解型別 */
        ANNOTATION_TYPE,
        /** 包 */
        PACKAGE
    }
    複製程式碼
  • @Retention

    生命週期描述

    public enum RetentionPolicy {
        /**
         * 在原檔案中有效,被編譯器丟棄。 
         */
        SOURCE,
        /**
         * 在class檔案有效,可能會被虛擬機器忽略。 
         */
        CLASS,
        /**
         * 在執行時有效。
         */
        RUNTIME
    }
    複製程式碼
  • @Inherited

    標識性的元註解,它允許子註解繼承它。

  • @Documented

    用於標準生成javadoc時會包含的註解。

JAVA中註解的定義方式

public @interface 註解名 {定義體}
複製程式碼

上面試一些基本概念點,關注註解其他的一些特性和用法就不細說了。直接看Spring中的註解吧。

1、@Component

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any
     */
    String value() default "";

}
複製程式碼

指示註釋類是“元件”。 當使用基於註釋的配置和類路徑掃描時,這些類被認為是自動檢測的候選物件。

2、@Controller

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    String value() default "";
}
複製程式碼

使用過Spring mvc的小夥伴對於這個註解肯定不陌生。@Controller表示註釋的類是“控制器”(例如Web控制器)。這個註解作為@Component的一個特定方式存在,允許通過類路徑掃描來自動檢測實現類。通常情況下會結合RequestMapping註解使用。從它的定義層面來看,這個註解只能用於介面或者類上面,不能用於方法或者屬性欄位上面。

3、@Service

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
	String value() default "";
}
複製程式碼

表示註釋類是一個“服務”,最初由Domain-Driven Design (Evans,2003)定義為“作為模型中獨立的介面提供的操作,沒有封裝狀態”。

在一般情況下,我們把他用在標準我們的service服務介面的實現類上面,實際上這相當於縮小它們的語義和適當的使用。

@Service這個註釋作為 @Component的一個特例,允許通過類路徑掃描來自動檢測實現類。

4、@Repository

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any
     */
    String value() default "";
}
複製程式碼

用於標註資料訪問元件,即DAO元件

5、@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 {};

}
複製程式碼

@RequestMapping是一個用來處理地址對映請求的註解,從定義可以看出,可作用於方法或者類上。

  • 用於類上,大多數是為了進行區分controller
  • 用於方法上則是對方法進行註解以產生訪問的路徑。

它包括了幾個屬性:

  • value 用於設定方法或者類的對映路徑,可以直接寫路徑。我們通常都是直接寫,例如:@RequestMapping("/XXX");
  • method 用於指定請求的方法,可以設定單個或多個,如果請求方法不滿足條件則會請求失敗。
  • params 指定request中必須包含某些引數值是,才讓該方法處理。
  • name 此對映指定一個名稱
  • path 僅在Servlet環境中:路徑對映URI(例如“/myPath.do”)。也支援Ant風格的路徑模式(例如“/myPath/*.do”)。在方法級別,在型別級別表示的主對映內支援相對路徑(例如“edit.do”)。 路徑對映URI可能包含佔位符(例如“/ $ {connect}”)
  • consumes 指定處理請求的提交內容型別(Content-Type),例如application/json, text/html;
  • produces 指定返回的內容型別,僅當request請求頭中的(Accept)型別中包含該指定型別才返回;
  • headers 指定request中必須包含某些指定的header值,才能讓該方法處理請求。

其他的幾個沒怎麼用過,確實不瞭解,有知道的小夥伴,歡迎留言。

6、@ResponseBody

@ResponseBody這個我一般是用在做非同步請求呼叫的方法上來使用的。因為在使用@RequestMapping後,返回值通常解析為跳轉路徑。加上@responsebody後,返回結果直接寫入HTTP response body中,不會被解析為跳轉路徑。

對於非同步請求,我們不希望返回解析檢視,二是希望響應的結果是json資料,那麼加上@responsebody後,就會直接返回json資料。

7、@Autowired

Autowired就是自動裝配的意思,其作用是為了消除程式碼Java程式碼裡面的getter/setter與bean屬性中的property。當然,getter看個人需求,如果私有屬性需要對外提供的話,就應該保留。

@Autowired預設按型別匹配的方式,在容器查詢匹配的Bean,當有且僅有一個匹配的Bean時,Spring將其注入@Autowired標註的變數中。

但是當介面存在兩個實現類的時候必須使用@Qualifier指定注入哪個實現類,否則可以省略,只寫@Autowired。

8、@Qualifier

@Qualifier用於指定注入Bean的名稱,就是上面說到的,如果容器中有一個以上匹配的Bean,則可以通過@Qualifier註解限定Bean的名稱。

9、@Resource

這個註解不是Spring的,放在這裡是為了和@Autowired做一個區別。 @Resource預設按名稱裝配,當找不到與名稱匹配的bean才會按型別裝配。

10、@PathVariable

當使用@RequestMapping URI template 樣式對映時, 即 someUrl/{paramId}, 這時的paramId可通過 @Pathvariable註解繫結它傳過來的值到方法的引數上。

@RequestMapping("/user/{userId}")
public ModelAndView userCenter(HttpServletRequest request,
                            HttpServletResponse response,
                            @PathVariable String userId){
    //do something 
}
複製程式碼

如果方法引數名稱和需要繫結的uri template中變數名稱不一致,需要在@PathVariable("name")指定uri template中的名稱。

11、@RequestParam

@RequestParam註解有兩個屬性: value、required;

  • value用來指定要傳入值的id名稱
  • required用來指示引數是否必須繫結;

舉個例子:

@RequestMapping("/t_rparam1")  
public String t_rparam1(@RequestParam  Long userId) {  
    //do something   
}  

@RequestMapping("/t_rparam2")  
public String t_rparam2(Long userId) {  
    //do something   
}
複製程式碼
  • t_rparam1 必須帶有引數,也就是說你直接輸入localhost:8080/t_rparam1 會報錯只能輸入localhost:8080/t_rparam1?userId=? 才能執行相應的方法
  • t_rparam2 可帶引數也可不帶引數;也就是說輸入localhost:8080/t_rparam2和輸入 localhost:8080/t_rparam2?userId=?都可以正常執行

當然我們也可以設定 @RequestParam 裡面的required為false(預設為true 代表必須帶引數) 這樣t_rparam1就跟t_rparam2是一樣的了。

12、@RequestHeader

利用@RequestHeader 註解可以把Request請求header部分的值繫結到方法的引數上。

Spring原始碼系列:註解說明

@RequestMapping("/t_heander")  
public void getRequestHeaderTest(HttpServletRequest request,
                            HttpServletResponse response,
                            @RequestHeader("Accept-Encoding")String encoding)  {  
  
  //do something 
} 
複製程式碼

13、@CookieValue

@CookieValue就是把Request header中cookie的值繫結到方法的引數上。比如說我們的cookie如下:

Cookie:JSESSIONID=ka8A5L5t7WTUPXbaLupBieqOdmc0ZpD5MyKvea6oQr7JJSIZzM;userId=001;sysFlag=glmapper
複製程式碼

獲取如下:

@RequestMapping("/t_cookie")  
public void getCookieValueTest(@CookieValue("JSESSIONID") String cookie)  {  
  //do something 
} 
複製程式碼

14、@RequestBody

@RequestBody這個註解常用來處理Content-Type不是application/x-www-form-urlencoded編碼的內容,比如說:application/json, application/xml等等;這個和ResonseBody可以反過來理解。

15、@ModelAttribute

  • 方法上

    通常用來在處理@RequestMapping之前,為請求繫結需要從後臺查詢的model;

  • 引數上

    用來通過名稱對應,把相應名稱的值繫結到註解的引數bean上;

參考

  • 《Spring技術內幕》
  • https://www.cnblogs.com/FrankLei/p/6579843.html

相關文章