1. 程式人生 > >【譯】spring註解程式設計模型

【譯】spring註解程式設計模型

原文連結: https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model#stereotype-annotations

原文連結: https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model#stereotype-annotations

本文內容

  1. 概觀
  2. 術語
  3. 例子
  4. 常問問題

一、概觀

多年來,Spring Framework不斷髮展對註解的支援,比如元註解和組合註解的支援。本文件旨在幫助開發人員(Spring的終端使用者,Spring Framework和Spring組合專案的開發人員)開發和使用Spring註解。

二、本文件的目標

本文件的主要目標包括以下內容的解釋:

  • 如何使用Spring註釋。
  • 如何開發用於Spring的註釋。
  • Spring如何找到註釋(即Spring的註釋搜尋演算法如何工作)。

三、本文件的非目標

本文件的目的不是說明Spring Framework中特定註釋的語義或配置選項。需要檢視相關關特定註釋的詳細資訊,建議開發人員查閱相應的Javadoc或參考官網文件的相應部分。

四、術語

1.元註解

元註釋是java基礎註解來宣告註解。因此,一個註解必然是被元註解而註解的。例如,任何註解被宣告都是 @Documented從java.lang.annotation包中進行元註釋的。

2.模式註解

模式註解是被用於宣告在應用程式中個一個元件的角色。例如,@Repository 註解在Spring Framework中是任何滿足儲存庫角色或構造型(也稱為資料訪問物件或DAO)的類的標記。

@Component是任何Spring管理元件的通用模式註解。任何被 @Component 標準的元件均為元件掃描的候選物件。類 似地,凡是被 @Component 元標註(meta-annotated)的註解,如 @Service,當任何元件標註它時,也被視作元件掃 描的候選物件。

核心Spring提供了一些模式註解開箱即用,包括但不限於:@Component,@Service,@Repository, @Controller,@RestController,和@Configuration。@Repository, @Service等等都是@Component的擴充套件化。

3.組合註釋

組合註解是元註解與相結合的那些元註釋相關聯成一個單一的自定義註解的行為的意圖的一個或多個註解。例如,一個名為@TransactionalService使用Spring裡面的 @Transactional和@Service註釋進行註解的註解是一個組合註釋,它結合了@Transactional和@Service的語義。 @TransactionalService是在技​​術上自定義的一個模式註解。

4.註釋存在

一個註解無論是直接標註還是間接標註一個bean,這個註解在java8的java.lang.reflect.AnnotatedElement類註釋中所約定的含義和特性都不會有任何改變。
在Spring框架裡面,註釋被認為是元存在,如果註釋被宣告為一些其他的註釋的元註釋這是一個元件上存在的元件上。例如,鑑於上述 @TransactionalService,我們可以說,@Transactional是元存在 於直接與註釋的任何類@TransactionalService。

5.屬性別名和覆蓋

一個屬性別名是從一個註釋屬性到另一個註釋屬性的別名。一組別名中的屬性可以互換使用,並視為等效。屬性別名可以分類如下。

顯式別名:如果一個註釋中的兩個屬性被宣告為彼此的別名@AliasFor,則它們是顯式別名。
隱式別名:如果一個註釋中的兩個或多個屬性被宣告為元註釋中相同屬性的顯式覆蓋@AliasFor,則它們是隱式別名。
傳遞隱式別名:在一個註釋中給出兩個或多個屬性,這些屬性被宣告為元註釋中屬性的顯式覆蓋@AliasFor,如果屬性有效地覆蓋了遵循傳遞定律的元註釋中的相同屬性 ,則它們是傳遞隱式別名。

一個屬性重寫是一個重寫(或陰影)在元註釋的註釋屬性。屬性覆蓋可以分類如下。

隱式覆蓋:給定的屬性A中的註解@One和屬性A的標註@Two,如果@One是元註解為@Two,然後在屬性A中的註釋@One是一個隱含的倍率為屬性A的標註@Two只在命名約定為主(即,兩個屬性被命名A)。

顯示覆蓋:如果屬性A被宣告為屬性的別名B在通過元註釋@AliasFor,則A是一個明確的覆蓋了B。

傳遞明確覆蓋:如果註解@One中的成員A明確覆蓋了註解@Two中的成員B,而且成員B實際覆蓋了註解@Three中的成員C,那麼因為覆蓋的傳遞性,所以成員A實際覆蓋了成員C。

五.例子

Spring Framework和Spring portfolio (https://github.com/sbrannen/spring-polyglot) 專案中的許多註釋都使用@AliasFor註釋來宣告屬性別名和屬性覆蓋。常見的例子包括@RequestMapping, @GetMapping和@PostMapping從Spring MVC的以及註釋,比如@SpringBootApplication和@SpringBootTest從Springboot啟動。

以下部分提供了演示這些功能的程式碼段。

1.使用@AliasFor宣告屬性別名

Spring Framework 4.2引入了一流的支援,用於宣告和查詢註釋屬性的別名。該@AliasFor註釋可被用於宣告一對混疊屬性內的單個註釋或從在自定義由註釋一個屬性宣告的別名在元註釋的屬性。

例如,@ContextConfiguration從spring-test模組宣告如下。

public  @interface  ContextConfiguration { @AliasFor(“ locations ”)
     String [] value()default {}; @AliasFor(“ value ”)
     String [] locations()default {}; // ... 
}

該locations屬性被宣告為屬性的別名value ,反之亦然。因此,以下宣告@ContextConfiguration是等效的。

@ContextConfiguration(“/ test-config.xml ”)
 public  class  MyTests { / * ... * / }
@ContextConfiguration(value  =  “/ test-config.xml ”)
 public  class  MyTests { / * ... * / }
@ContextConfiguration(locations  =  “/ test-config.xml ”)
 public  class  MyTests { / * ... * / }
 

類似地,從元註釋中覆蓋屬性的組合註釋可@AliasFor用於精確控制在註釋層次結構中覆蓋哪些屬性。實際上,甚至可以為value元註釋的屬性宣告別名。

例如,可以使用自定義屬性覆蓋開發組合註釋,如下所示。

@ContextConfiguration
public @interface MyTestConfig {

    @AliasFor(annotation = ContextConfiguration.class, attribute = "value")
    String[] xmlFiles();

    // ...
}

上面的示例演示了開發人員如何實現自己的自定義組合註釋 ; 然而,以下表明Spring本身在許多核心Spring註釋中使用了這個特性。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {

    /**
     * Alias for {@link RequestMapping#name}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String name() default "";

    /**
     * Alias for {@link RequestMapping#value}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] value() default {};

    /**
     * Alias for {@link RequestMapping#path}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] path() default {};

    // ...
}

2.Spring Composed和Spring Polyglot

Spring Composed專案是可以在在spring4.2.1和更高版本中使用的一系列組合註解。你可以在Spring MVC使用像@Get,@Post,@Put, 和@Delet這樣的註解,也可以在Spring MVC REST應用中使用@GetJson,@PostJson等等註解。

如果你確信已經學習了足夠深入的spring-composed例子,汲取了足夠多的靈感,然後你可以為spring-Composed專案貢獻出由你自定義的組合註解!

https://github.com/sbrannen/spring-composed
https://github.com/sbrannen/spring-polyglot

六、FAQ

1)可以@AliasFor與value屬性一起使用@Component和@Qualifier?
最簡潔的答案是:不可以。

將value在屬性@Qualifier和模式註解(例如@Component,@Repository,@Controller,和任何自定義典型化註解)不能受其影響@AliasFor。原因是這些value屬性的特殊處理是在@AliasFor發明之前的幾年。因此,由於向後相容性問題,根本不可能使用@AliasFor這些value屬性。

七、待發掘主題

  • 記述 註解和標註了註解和元註解的類、介面、成員方法、成員變數、引數的通用搜索演算法。
    1. 如果一個註解既是以註解又是以元註解的方式標註了一個元素會發生什麼呢?
    2. 一個註解標註了@Inherited(包括自定義組合註解)後,是如何對搜尋演算法產生影響呢?
  • 記述 通過@AliasFor配置註解成員別名的技術原理。
    1. 如果一個成員和它的別名都宣告在一個註解例項(成員和別名值相同或者不同時)中在技術上會發生什麼?
    2. 較有代表性的一種情況是,一個AnnotationConfigurationException將會被丟擲。
  • 記述_組合註解_的技術原理。
  • 記述 組合註解成員覆蓋元註解成員的原理。
    1. 詳細記述 查詢成員的演算法原理:
      • 基於命名約定的間接覆蓋(換句話說,組合註解中有明確名字和型別的成員去覆蓋元註解的成員)
      • 使用@AliasFor來直接覆蓋
    2. 如果一個成員和它的眾多別名中的一個在註解繼承的某一層級中被重新聲明瞭會發生什麼?哪個會生效?
    3. 總之,成員變數宣告時的衝突是怎麼被解決的?

關注個人公眾號:coder辰砂 ,目前正在慢慢的整理,前期還是基礎技術部分整理