Spring2.5新特性

生之初,Spring框架就守它的宗旨:化企業級應用開,同時給雜問題提供大的、非侵入性解決方案。一年前布的Spring2.0就把些主推到了一個新的高度。XML Schema的支持和自定命名空的使用大大減少了基於XML的配置。使用Java5及更新版本java的開如今可以利用植入了像泛型generic)和註解等新言特性的Spring。最近,和AspectJ表達式言的密集成,使得以非侵入方式添加跨越定良好的Spring管理象分的行可能。

布的Spring2.5繼續堅持了向,特那些使用Java 5或更新版本java的開提供了一步化而大的新特性。些新特性包括:註解驅動的依性注入(annotation-driven dependency injection),使用註解而非XML元數據來自動偵測classpath上的Spring件,註解命週期方法的支持,一個新的web控制器模型將求映射到加註解的方法上,在測試框架中支持Junit4Spring XML命名空的新增內容,等等。

本文是探討這些新特性的3篇系列文章中的第一篇。本文將主要關注於化的配置和在Spring用程序上下文(application context)核心新增的基於註解的功能;第二篇文章將涵蓋web可用的新特性;最後一篇文章將着重介集成和測試的新增性能。一系列的三篇文章中引用的例子都基於Spring PetClinic用程序範例。此範例最近被重構以用於展示Spring最新功能,並被包含於Spring 2.5佈下包中,可以從Spring Framework "samples/petclinic"下的"readme.txt"文件可以得知關於如何構建和部署PetClinic用程序,掌握本文提到的新技的最佳方法也就是PetClinic用程序中所展示的特性試驗

Spring支持JSR-250註解

Java EE5中引入了“Java平臺的公共註解(Common Annotations for the Java Platform,而且公共註解從Java SE 6一開始就被包含其中。 20065月,BEA宣佈了他在一個名Pitchfork目上與Interface21合作該項目提供了基於SpringJava 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支持使用@ResourceJNDI lookup來解析象,默地,有與@Resource註解所提供名字相匹配的“bean namebean名字)Spring管理象會被注入。 在下面的例子中,Spring會向加了註解的setter方法傳遞beandataSourceSpring管理象的引用。

@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開始添加命名空以來,定一個委託SpringJNDI lookupbean得愈發簡練

<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之前版本中提供的同的回調的另兩個選項。第一個選項實現SpringInitializingBean DisposableBean 接口中的一個或兩個。兩個接口都需要一個回調方法的實現(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註解的所有行,正如上文提到的,需要SpringCommonAnnotationBeanPostProcessor提供一個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-processorAutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor)和我Spring2.0中引入的基於註解的post-processorRequiredAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor

<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中提供一個CustomAutowireConfigurerbean並直接註冊所有自定註解型:

<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();
 
}

自定屬性可以匹配那些XMLbeanqualifier註解的屬性子元素。些元素通常以值對方式提供。

<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;

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

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

動偵測Spring

2.0版本開始,Spring引入了構造型(stereotype)註解的概念以及將@Repository註解作數據訪問標記的方法。在此基上,Spring2.5又加入了兩個新的註解 —— @Service@Controller 來完成通常的三架構(數據訪問對象、服web控制器)角色委任。Spring2.5也引入了泛型@Component註解,其他構造型可從邏輯展。通清晰地指明用程序的角色,些構造型方便了Spring AOPpost-processor的使用,post-processor基於些角色的加了註解的象提供了附加行。比如,Spring2.0引入了PersistenceExceptionTranslationPostProcessor任何@Repository 註解的象自激活其數據訪問異常轉換

些註解同可以Spring2.5其他一些新性能來使用:自動偵測classpath上的件。盡XML最常Spring元數據的格式,但它決不是唯一選擇實際上,Spring容器內的元數據是由Java來表示的,當XML被用來定Spring管理,在例化程之前,那些定會被解析並化成Java象。Spring2.5的一個巨大的新功能是支持從源碼層註解取元數據。因而,上文描述的自裝配機制使用註解的元數據來注入依,但它仍然需要註冊至少一個bean以便提供每個Spring管理象的實現類描功能使得XML中最起bean都不再存在需求性。

正如上面所示,Spring註解驅動的自裝配可以在不粒度控制的前提下極大程度地減少XML的使用。偵測機制將點更發揚光大。全面替代XML中的配置不再必要,描反而可以XML元數據來化整體配置。XML和註解驅動可以得到一個平衡化的方法,2.5版本的PetClinic範例中有詳細闡述。在範例中,基構架件(數據源、事管理等)合上文提到的外化屬性在XML中定。數據訪問層對象也有部分在XML中定,它的配置也都利用了@Autowired註解來化依注入。最後,web控制器完全不XML式定,相反,下面提供的段配置被用來觸所有web控制器的自動偵測

<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
 

需要注意到的是段示例中使用到了base-package屬性。描的默匹配規則遞歸偵測該包(多個包可以以逗號分隔的list方式提供)內的所有的所有Spring構造型註解。正因如此,PetClinic用程序範例中的各控制器的實現都採用了@Controller註解(Spring內置構造型之一)。看下面個例子:

@Controller
public class ClinicController {
 
  
private final Clinic clinic;
 
   @Autowired
  
public ClinicController(Clinic clinic) {
         
this.clinic = clinic;
   }
 ...

動偵測組件在Spring容器中註冊,就像它XML中被定。如上所示,那些象可以流利用註解驅動的自裝配。

描的匹配規則可以通過過濾器(filter)來自定,以根據型、AspectJ表達式、或針對命名模式的正表達式來決定包含或不包含哪些件。默的構造型也可以被禁用。比如裏有一個配置的例子,個配置會忽略默的構造型,但會自動偵測名字以Stub或者包含@Mock註解的所有

<context:component-scan base-package="example" use-default-filters="false">
  
<context:include-filter type="aspectj" expression="example..Stub*"/>
  
<context:include-filter type="annotation" expression="example.Mock"/>
</context:component-scan>

型匹配的限制性也可以用排他的過濾器控制。例如,除了@Repository註解外其他都依於默認過濾器,那麼就需要加入一個排他過濾(exclude-filter)

<context:component-scan base-package="example">
  
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

很明,有很多方法可以描來註冊自定型。構造型註解是最簡單選擇,所以構造型概念本身也是可展的。像先前提到的,@Component泛型模型,@Repository@Service,@Controller註解都從構造型邏輯擴展而得。正因如此,@Component可被用來作元註解(也就是,在另外的註解上聲明的註解),所有具有@Component元註解的自定註解都會被默認掃描匹配規則動偵測到。一個例子就有希望會到其它根本沒有聽起來那麼

回想一下在@PostConstruct@PreDestroy生命週期註解的候的假想的後臺任一個用程序有很多很多這樣的後臺任些任務實例需要XML bean以便在Spring context裏註冊並使它自己的生命週期方法在正確候被調用。利用描就不再需要式的XML bean。如果些後臺任實現一個相同的接口或者都沿用同的命名例,那麼可以用include-filters。然而,更簡單的方法是爲這些任務對建一個註解並提供@Component元註解。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
   String value()
default "";
}

然後在所有後臺任中提供自定構造型註解。

@BackgroundTask
public class FilePoller {
 
   @PostConstruct
  
public void startPolling() {
         ...
   }
 
   @PreDestroy
  
public void stopPolling() {
         ...
   }
   ...
}

泛型@Component註解可以像例子中提供的那樣簡單使用,自定註解技術則提供了一個使用更具涵的、域特定的名字的機會。域特定註解提供更深入的機會,比如使用AspectJ切點表達式來識別所有後臺任,以便增加advice些任的活性。

的,件被偵測到的候,Spring會自生成一個沒有修符的名作bean名字。上一個例子中,生成的bean名字會是filePoller。但是,任何加註了Spring構造型註解(@Component@Repository@Service @Controller)或是加註了其他的以@Component元註解的註解(比如上面例子中的@BackgroundTask )的,構造型註解的value屬性可以被式指定,例將該值它的bean名字註冊到context中。接下來的例子裏,例名應該petClinic而不是默生成的名字simpleJdbcClinic

@Service("petClinic")
public class SimpleJdbcClinic {
   ...
}

的,在下面修正版的FilePoller例子裏,生成的bean名字應該poller而不是filePoller

@BackgroundTask("poller")
 
public class FilePoller {
   ...
}

然所有Spring管理象都被默地當作例來理,但有些是有必要某個象指明一個用的範scope)。個例子來,在web,一個Spring管理象可能捆requestsession的範2.0版本,Springscope機制更具延展性,這樣一來,自定scope可以被註冊到用程序上下文(application context)。在XML配置中,僅僅簡單地包含scope屬性及scope的名字就可以了。

<bean id="shoppingCart" class="example.ShoppingCart" scope="session">
   ...
</bean>

Spring2.5中,描的件提供@Scope註解可以起到同的作用。

@Component
@Scope("session")
public class ShoppingCart {
   ...
}

裏要指出的最後一點是使用qualifier註解用是多麼的簡單。在上一,下面象曾被作使用自定qualifier註解行自裝配的例子:

@VetSpecialty("dentistry")
private Clinic dentistryClinic;

的例子接着展了在XML內使用‘qualifier’元素提供指定目bean。在使用XML元數據不是必的。但自定符也在目標類中被作爲類註解而引入。另一個將被描的@Repository例作的例子如下:

@Repository
@VetSpecialty("dentistry")
public class DentistryClinic implements Clinic {
   ...
}

,因前面的例子展了自定註解及其屬性的例子,相等同的非XML表示依的方法如下:

@Repository
@SpecializedClinic(species="dog", breed="poodle")
public class PoodleClinic implements Clinic {
   ...
}

Spring2.5在很多方面都提供了很有意的新功能。本文主要關注於怎掌控Java註解的力量將配置化。就如在JSR-250中定的那Spring支持公共註解(Common Annotations),同時爲裝配程的更粒度的控制提供了外註解。Spring2.5展了從Spring2.0@Repository就開始的構造型(stereotype)註解,並且所有些構造型註解都可以和新的描功能合使用。Spring2.5仍然全面支持基於XML的配置,同它又引了一個新的context命名空間對配置景提供更精要的文法。實際上,支持XML和基於註解配置的無縫結合最終產生一個更平衡的全面的方法。基本構架的復配置可以在模XML文件中定,而用程序日益增多地更高配置可以更多的從基於註解的技——前提是都在同一個Spring2.5用程序context內。

在接下來的文章中,我討論到在Spring web層強大的基於註解的新功能。敬關注系列的下一篇文章

 

發佈了18 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章