Spring JSR-250註解-1

轉載來源: http://www.infoq.com/cn/articles/spring-2.5-part-1

註釋配置相對於 XML 配置具有很多的優勢:

  • 它可以充分利用 Java 的反射機制獲取類結構信息,這些信息可以有效減少配置的工作。如使用 JPA 註釋配置 ORM 映射時,我們就不需要指定 PO 的屬性名、類型等信息,如果關係表字段和 PO 屬性名、類型都一致,您甚至無需編寫任務屬性映射信息——因爲這些信息都可以通過 Java 反射機制獲取。
  • 註釋和 Java 代碼位於一個文件中,而 XML 配置採用獨立的配置文件,大多數配置信息在程序開發完成後都不會調整,如果配置信息和 Java 代碼放在一起,有助於增強程序的內聚性。而採用獨立的 XML 配置文件,程序員在編寫一個功能時,往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會降低開發效率。

因此在很多情況下,註釋配置比 XML 配置更受歡迎,註釋配置有進一步流行的趨勢。Spring 2.5 的一大增強就是引入了很多註釋類,現在您已經可以使用註釋配置完成大部分 XML 配置的功能。在這篇文章裏,我們將向您講述使用註釋進行 Bean 定義和依賴注入的內容。

Java EE5中引入了“Java平臺的公共註解(Common Annotations for the Java Platform)”,而且該公共註解從Java SE 6一開始就被包含其中。 2006年5月,BEA系統宣佈了他們在一個名爲Pitchfork的項目上與Interface21的合作,該項目提供了基於Spring的Java EE 5編程模型的實現,包括支持用於注入(injection)、攔截( interception)和事務處理(transactions)的JSR-250註解和EJB 3註解(JSR-220)。 在2.5版本中,Spring框架的核心(core)現在支持以下JSR-250註解:

  • @Resource
  • @PostConstruct
  • @PreDestroy

結合Spring,這些註解在任何開發環境下都可以使用——無論是否有應用程序服務器——甚至是集成測試環境都可以。激活這樣的支持僅僅是註冊一個單獨的Spring post-processor的事情:

 

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/> 

 

 


@Resource註解

@Resource 註解被用來激活一個命名資源(named resource)的依賴注入,在JavaEE應用程序中,該註解被典型地轉換爲綁定於JNDI context中的一個對象。 Spring確實支持使用@Resource通過JNDI lookup來解析對象,默認地,擁有與@Resource註解所提供名字相匹配的“bean name(bean名字)”的Spring管理對象會被注入。 在下面的例子中,Spring會向加了註解的setter方法傳遞bean名爲“dataSource”的Spring管理對象的引用。

 

@Resource(name="dataSource") public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } 

 

 


直接使用@Resource註解一個域(field)同樣是可能的。通過不暴露setter方法,代碼愈發緊湊並且還提供了域不可修改的額外益處。正如下面將要證明的,@Resource註解甚至不需要一個顯式的字符串值,在沒有提供任何值的情況下,域名將被當作默認值。

 

@Resource private DataSource dataSource; // inject the bean named 'dataSource' 

 

 


該方式被應用到setter方法的時候,默認名是從相應的屬性衍生出來,換句話說,命名爲'setDataSource'的方法被用來處理名爲'dataSource'的屬性。

 

private DataSource dataSource; @Resource public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } 

 

 


@Resource沒有顯式提供名字的時候,如果根據默認名字找不到對應的Spring管理對象,注入機制會回滾至類型匹配(type-match)。如果剛好只有一個Spring管理對象符合該依賴的類型,那麼它會被注入。通過設置CommonAnnotationBeanPostProcessor‘fallbackToDefaultTypeMatch’屬性爲“false”(默認值是“true”)可以禁用這一特性。

 

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"> <property name="fallbackToDefaultTypeMatch" value="false"/> </bean> 

 

 


正如上文所提到的,在解析標有@Resource註解的依賴時,Spring支持JNDI-lookup。如若要強制對所有使用@Resource註解的依賴進行JNDI lookup,那也只要將CommonAnnotationBeanPostProcessor'alwaysUseJndiLookup' 標識設置爲true就可以了(默認值是false)。

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"> <property name="alwaysUseJndiLookup" value="true"/> </bean>

 

 


另一個選擇是,激活指定爲‘resource-ref-mappings’的依據全局JNDI名的查找,在@Resource註解內提供‘mappedName’屬性。即使目標對象實際上是一個JNDI資源,仍然推薦引入一個Spring管理對象,這樣可以提供一個間接層並且因此降低耦合程度。自Spring2.0開始添加命名空間以來,定義一個委託Spring處理JNDI lookup的bean也變得愈發簡練:

 

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/> 

 

 


這個方法的優點在於間接層帶來了巨大的部署彈性。比如說,一個單獨的系統測試環境應該不再需要JNDI註冊。在這種情況下,在系統測試配置中可以提供如下的bean定義:

 

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/> 

 

 


順便提一下,上面的例子中,實際的JDBC連接屬性從一個屬性文件(properties file)解析而來,在這個屬性文件裏,關鍵字與提供的${佔位符}互相對應,這需要註冊一個名爲PropertyPlaceholderConfigurerBeanFactoryPostProcessor實現來完成。這是具體化那些屬性(通常是針對特定環境的屬性)常用的技術,這些屬性可能比其他配置修改得更爲頻繁。

 

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> </bean> 

 

 


Srping2.5中新加入了‘context’命名空間,這個命名空間讓我們能夠得到更爲簡潔的方式來實現屬性佔位符(property placeholder)的配置:

 

<context:property-placeholder location="classpath:jdbc.properties"/>

 

 


生命週期註解:@PostConstruct和@PreDestroy

@PostConstruct@PreDestroy註解分別用來觸發Spring的初始化和銷燬回調。這個特性在原有基礎上得到了擴展,但並沒有替代在Spring2.5之前版本中提供的同樣的回調的另兩個選項。第一個選項是實現Spring的InitializingBeanDisposableBean 接口中的一個或兩個。這兩個接口都需要一個回調方法的實現(分別是afterPropertiesSet()destroy() )。這種基於接口的方法利用了Spring自動識別任何實現這些接口的Spring管理對象的能力,因而不再需要另外的配置。另一方面,Spring的一個關鍵目標是儘可能的非侵入。因此,許多Spring用戶並不採用實現這些Spring特定接口的方法,而利用第二個選項,那就是提供他們自己的初始化和銷燬方法。儘管入侵性小,但缺點在於使用這個方式的話就必須顯式聲明bean元素的init-methoddestroy-method屬性。顯式配置有時候是必須的,例如當回調需要在開發人員控制能力之外的代碼上被調用的時候。PetClinic應用程序很好地說明了這個場景。當它和JDBC配置一起運行的時候,會用到一個第三方DataSource,並且它顯式聲明瞭一個destroy-method。另外要注意到的是,單獨的連接池數據源是dataSource的另一個部署選項,並且不需要修改任何代碼。

 

<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close" p:driverClassName="${jdbc.driverClassName}"p:url="${jdbc.url}"p:username="${jdbc.username}"p:password="${jdbc.password}"/> 

 

 


在使用Spring2.5的過程中,如果一個對象需要調用一個初始化的回調方法的話,這個回調方法可以採用@PostConstruct來註解。例如一個假想的例子,一個後臺任務需要在啓動的時候就開始對一個文件目錄進行輪詢:

 

public class FilePoller {   @PostConstruct   public void startPolling() {       }   } 

 

 


類似地,一個在Spring管理對象上用@PreDestroy註解的方法會在這個對象寄宿的應用程序上下文(application context)關閉的時候被調用。

 

public class FilePoller { @PreDestroy public void stopPolling() { } } 

 

 


在添加了對JSR-250註解的支持以後,現在的Spring2.5結合前面提到的兩種生命週期方法的長處。將@PostConstruct@PreDestroy作爲方法層註解加入,足可以實現在受Spring管理的上下文(context)中觸發回調。換句話說,不需要另外基於XML的配置。同時,這兩個註解是Java語言本身的一部分(甚至被包括在Java SE 版本6中),所以無需引入特定Spring包。這兩個註解擁有在其他環境中也能理解的標識語義的優點,隨着時間的推移,Java開發人員可能會發現這些註解在第三方開發庫中被越來越多的運用到。最後,基於註解生命週期回調的其中一個有趣的結果是,不止一個方法可以帶有這兩個註解中的任何一個,並且所有註解了的方法會被調用。

激活剛剛描述的關於@Resource@PostConstruct@PreDestroy註解的所有行爲,正如上文提到的,需要爲Spring的CommonAnnotationBeanPostProcessor提供一個bean定義。但另一個更簡練的方法則可能是使用2.5中的新的context命名空間:

 

<context:annotation-config/>

 

 


引入這個單個元素將不單單註冊一個CommonAnnotationBeanPostProcessor,也會像下文將敘述的那樣激活自動裝配(autowire)行爲。CommonAnnotationBeanPostProcessor也爲@WebServiceRef@EJB註解提供支持。這些將在本文系列的第三篇中和Spring2.5爲企業集成提供的其他新特性一起討論。

利用註解來優化細粒度自動裝配

涵蓋Spring對自動裝配支持的文檔中常常會提到由於自動裝配機制的粗粒度而伴隨有很多限制性。Spring2.5之前,自動裝配可以通過很多不同的方式來配置:構造器,類型setter,名字setter,或者自動偵測(在該方式中Spring選擇自動裝配一個構造器或者類型setter)。這些不同的選擇確實提供了很大程度的靈活性,但它們中沒有一個方法能夠提供細粒度控制。換句話說,Spring2.5之前還不可能自動裝配某個對象setter方法的特定子集,或者通過類型或名字來自動裝配它的一些屬性。結果,許多Spring用戶意識到將自動裝配應用到構建原型和測試中的好處,但當提到在產品中維護和支持系統時,大部分人認爲,加入冗長的顯式配置對於澄清它所擔負的職責是非常值得的。

然而,Spring2.5大幅度地改變了佈局。如上文所述,自動配置選項現在已經被擴展,支持JSR-250 @Resource註解來激活在每個方法或域基礎上被命名資源的自動裝配。然而,@Resource註解若單獨使用的話有很多限制。因此,Sring2.5引進了一個名爲@Autowired的註解進一步提高控制級別。爲激活這裏所講的行爲需要註冊一個單獨的bean定義:

 

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

 

 


另外如上文提到的,context命名空間提供了一個更簡明的方法。它將激活本文所討論的兩個post-processor(AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor)和我們在Spring2.0中引入的基於註解的post-processor:RequiredAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor

 

<context:annotation-config/>

 

 


利用@Autowired 註解可以對相應類型注入依賴。域、構造器和方法都可以激活此行爲。實際上,aotowired方法並不一定要是setter方法,且可以接受多個參數。下面這個例子是完整的可接受的用法:

 

@Autowired public void setup(DataSource dataSource, AnotherObject o)  } 

 

 


默認地,標有@Autowired註解的依賴被認爲是必須的。然而,也可以將required屬性值設置爲false來聲明它們中的任何一個。在下面這個例子中,DefaultStrategy只有在context命名空間中沒有SomeStrategy類型的Spring管理對象時才能被使用。

 

@Autowired(required=false) private SomeStrategy strategy = new DefaultStrategy(); 

 

 


通過類型進行的自動裝配明顯地在Spring context包含多於一個期望類型的對象的時候造成歧義。默認地,如果一個必須的依賴沒不是恰好一個bean與之對應的話,自動裝配機制就會失敗。同樣的,對於任何一個可選屬性,如果它擁有一個以上的候選,也都會失敗(如果屬性可選且沒有任何候選可用的話,該屬性則會被簡單地跳過)。有很多不同的配置選項可以避免這些衝突。

若Context中擁有一個指定類型的一個主關鍵實例,對這個類型定義的bean定義應該包含‘primary’屬性。當Context中含有其他可用實例的時候這個方法就很適用,但那些非主關鍵實例總是顯式配置的。

 

<bean id="dataSource" primary="true"  /> 

 

 


在需要更多控制的時候,任何autowired的域、構造參數、或者方法參數可以進一步加註@Qualifier註解。qualifier可以包含一個字符串值,在這種情況下,Spring會試圖通過名字來找到對應的對象。

 

@Autowired @Qualifier("primaryDataSource") private DataSource dataSource; 

 

 


@Qualifier作爲一個獨立註解存在的主要原因是它可以被應用在構造器參數或方法參數上,但上文提到的@Autowired註解只能運用在構造器或方法本身。

 

@Autowired public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o)  } 

 

 


事實上,@Qualifier作爲一個單獨的註解在定製化方面提供了更多的好處。用戶自定義的註解在自動裝配過程中也可以起到qualifier的作用,最簡單的實現方式是在運用自定義註解的同時將@Qualifier作爲它的元註解。

 

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface VetSpecialty  } 

 

 


自定義註解可以選擇包含一個值來提供通過名字匹配的功能,但更普遍的用法是將它作爲“標記”註解或定義一個對qualifier過程提供一些更多含義的值。例如,下面這個摘錄則描繪了一個域,它應該和通過名字匹配得到的結果中合格的對象進行自動裝配。

 

@Autowired @VetSpecialty("dentistry") private Clinic dentistryClinic; 

 

 


在使用XML配置來達到依賴解析的目標時,'qualifier' 子元素可以被加註到bean定義中。在下文的組件掃描部分,我們將呈現一個可供選擇的非XML方法。

 

<bean id="dentistryClinic" class="samples.DentistryClinic"> <qualifier type="example.VetSpecialty" value="dentistry"/> </bean> 

 

 


爲了避免對@Qualifier註解的任何依賴性,可以在Spring context中提供一個CustomAutowireConfigurer的bean定義並直接註冊所有自定義註解類型:

 

<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer"> <property name="customQualifierTypes"> <set> <value>example.VetSpecialty</value> </set> </property> </bean> 

 

 


現在,自定義修飾符被顯式聲明瞭,就不再需要@Qualifier這個元註解符了。

 

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface VetSpecialty  } 

 

 


其實,在配置AutowiredAnnotationBeanPostProcessor的時候,取代@Autowired註解都是有可能的。

 

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"> <property name="autowiredAnnotationType" value="example.Injected"/> </bean> 

 

 


大部分情況下,定義自定義‘標記’註解的能力結合通過名字或其他文法值進行匹配選項,足以完成自動裝配過程的細粒度控制。但Spring還支持在qualifier註解上任意數目的任意屬性。比如,下面是一個極爲細粒度修飾的例子。

 

@SpecializedClinic(species="dog", breed="poodle") private Clinic poodleClinic; 

 

 


自定義修飾符的實現應該定義這些屬性:

 

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface SpecializedClinic { String species(); String breed(); } 

 

 


自定義修飾符屬性可以匹配那些XML中bean定義的qualifier註解的屬性子元素。這些元素通常以鍵/值對方式提供。

 

<bean id="poodleClinic" class="example.PoodleClinic"> <qualifier type="example.SpecializedClinic"> <attribute key="species" value="dog"/> <attribute key="breed" value="poodle"/> </qualifier> </bean> 

 

 


目前爲止,關於autowire的描述都只是針對單獨的實例,其實也支持集合。在任何需要得到所有context中某種特定類型的Spring管理對象的時候,只需要簡單地在一個強類型(strongly-typed)集合上加註@Autowired 註解。

 

@Autowired private List<Clinic> allClinics; 

 

 


本章節最後一個值得指出的特性是自動裝配的使用替代了Spring的Aware接口。在Spring2.5之前,如果某個對象需要一個Spring context的ResourceLoader的引用,它可以通過實現ResourceLoaderAware的方式使得Spring通過setResourceLoader(ResourceLoader resourceLoader)方法來提供該依賴。藉助同樣的方法可以得到Spring管理的MessageSource的引用,甚至可以得到ApplicationContext本身。對於Spring2.5用戶而言,這個行爲現在通過autowiring得到全面支持(需要指出的是包含這些Spring特定依賴的時候應該考慮周到,特別是它們只能用於從業務邏輯清楚地分割出來的基礎構架代碼中)。

 

@Autowired private MessageSource messageSource; @Autowired private ResourceLoader resourceLoader; @Autowired private ApplicationContext applicationContext;

 

 


 

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