Spring2.5的新特性:第一部分(三)

自動偵測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內。

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