









































































我們來看看上面代碼的含義,首先在代碼①和②處我們分別定義了兩個名為Foo和Bar的Bean,在③處我們通過set方法將兩個Bean注入進Base類中,并且在Base類中定義了toString方法來打印出Foo和Bar的信息,在④處我們定義了一個MainClass來執行我們的代碼,在⑤處我們通過getBean獲得配置文件中配置的id為base的Bean并在⑥出將其信息打印至控制臺,控制臺輸出信息如下:
Base : [The Foo's Name is : Tony The Foo's Age is : 27 The Bar's Address is : China Tianjin]
看到上面習以為常的配置信息和set get方法我們根本不會有任何想法,可是當我們看到了Spring2.5注釋特性的時候我們發現自己真的錯了,程序竟然還可以寫成這么簡單。
























我們在①和②處使用了@Autowired注釋,它可以對類的成員變量、方法及構造函數進行標注,完成自動裝配的工作,在③處我們為了使@Autowired注釋生效必須在Spring容器中聲明AutowiredAnnotationBeanPostProcessor Bean它通過掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 注釋時就找到和其相匹配(默認按類型匹配)的 Bean,并將其注入,而此時我們在聲明Base的時候(④處)就不用寫它的配置信息了,更可以將Base類中的set和get方法刪除。@Autowired還可以通過類的構造函數來進行自動裝配。
在默認情況下使用 @Autowired 注釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出 BeanCreationException 異常,并指出必須至少擁有一個匹配的 Bean














我們增加了一個構造函數,通過它來對我們的成員變量進行賦值,我們同時也為這個構造函數添加了@Autowired注釋(①處)使其可以自動將Foo和Bar兩個成員變量裝配進來。
當不能確定 Spring 容器中一定擁有某個類的 Bean 時,可以在需要自動注入該類 Bean 的地方可以使用 @Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時也不報錯




















①和②處我們分別定義了兩個類型為Bar的Bean,②處Bar的address為China Beijing并且Bean的名稱為bar2,在代碼清單4.2的③處我們同樣使用了@Autowired注釋為Bar的構造函數進行自動裝配,可是在④處我們通過@Qualifier("bar2")來明確指定我們需要將id為bar2的Bean裝配進來。我們還可以為成員變量使用@Qualifier注釋。











使用了@Autowired注釋后我們發現自動注入真的非常簡單,但是我們還是得在配置文件中定義相應的<Bean>,如果我們能在配置文件中完全移除Bean的定義那就更好了,Spring2.5就為我們提供了這一可能。

























我們使用了一個@Component注釋(①處),使用@Component 注釋就可以將一個類定義成為Spring 容器中的 Bean。在代碼清單5.2的②處我們也同樣使用了@Component注釋,而此時我們使用了它提供的一個可選的入參將Bean的名稱定義為base,最后在③處我們將以前定義Bean的內容全部移除,添加了一行<context:component-scan/>,其中的base-package屬性指定了需要掃描的類包,它會自動遞歸下面的子包。












在代碼清單6.1中的①處我們添加了一個@Scope注釋,這樣當我們從 Spring 容器中獲取 base 時,每次返回的都是一個新的實例了。
@Resource 的作用相當于 @Autowired,只不過 @Autowired 按 byType 自動注入,面 @Resource 默認按 byName 自動注入罷了。@Resource 有兩個屬性是比較重要的,分別是 name 和 type,Spring 將 @Resource 注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。如果既不指定 name 也不指定 type 屬性,這時將通過反射機制使用 byName 自動注入策略。
Resource 注釋類位于 Spring 發布包的 lib/j2ee/common-annotations.jar 類包中,因此在使用之前必須將其加入到項目的類庫中。來看一個使用 @Resource 的例子:













一般情況下,我們無需使用類似于 @Resource(type=Car.class) 的注釋方式,因為 Bean 的類型信息可以通過 Java 反射從代碼中獲取。
要讓 JSR-250 的注釋生效,除了在 Bean 類中標注這些注釋外,還需要在 Spring 容器中注冊一個負責處理這些注釋的 BeanPostProcessor:



七、使用@PostConstruct 和 @PreDestroy 注釋
Spring 容器中的 Bean 是有生命周期的,
























JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個注釋只能應用于方法上。標注了 @PostConstruct 注釋的方法將在類實例化后調用,而標注了 @PreDestroy 的方法將在類銷毀之前調用。
您只需要在方法前標注 @PostConstruct 或 @PreDestroy,這些方法就會在 Bean 初始化后或銷毀之前被 Spring 容器執行了。
我們知道,不管是通過實現 InitializingBean/DisposableBean 接口,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法,那些被標注 @PostConstruct 或 @PreDestroy 注釋的方法都會在初始化 / 銷毀時被執行。
七、使用 <context:annotation-config/> 簡化配置
Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供元數據信息。要使元數據信息真正起作用,必須讓負責處理這些元數據的處理器工作起來。
而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數據的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請看下面的配置:




















<context:annotationconfig/> 將隱式地向 Spring 容器注冊 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。
在配置文件中使用 context 命名空間之前,必須在 <beans> 元素中聲明 context 命名空間。
Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個擁有特殊語義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個注釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個注釋和 @Component 相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應用程序采用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。
在使用 @Component 注釋后,Spring 容器必須啟用類掃描機制以啟用注釋驅動 Bean 定義和注釋驅動 Bean 自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置:










這里,所有通過 <bean> 元素定義 Bean 的配置內容已經被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當然配置元數據還是需要的,只不過以注釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。
<context:component-scan/> 還允許定義過濾器將基包下的某些類納入或排除。Spring 支持以下 4 種類型的過濾方式,通過下表說明:
過濾器類型 說明
注釋 假如 com.baobaotao.SomeAnnotation 是一個注釋類,我們可以將使用該注釋的類過濾出來。
類名指定 通過全限定類名進行過濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。
正則表達式 通過正則表達式定義過濾的類,如下所示: com\.baobaotao\.Default.*
AspectJ 表達式 通過 AspectJ 表達式定義過濾的類,如下所示: com. baobaotao..*Service+






值得注意的是 <context:component-scan/> 配置項不但啟用了對類包進行掃描以實施注釋驅動 Bean 定義的功能,同時還啟用了注釋驅動自動注入的功能(即還隱式地在內部注冊了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),因此當使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了。
注釋配置不一定在先天上優于 XML 配置。如果 Bean 的依賴關系是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那么注釋配置優于 XML 配置;反之如果這種依賴關系會在部署時發生調整,XML 配置顯然又優于注釋配置,因為注釋是對 Java 源代碼的調整,您需要重新改寫源代碼并重新編譯才可以實施調整。
如果 Bean 不是自己編寫的類(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無法實施,此時 XML 配置是唯一可用的方式。
注釋配置往往是類級別的,而 XML 配置則可以表現得更加靈活。比如相比于 @Transaction 事務注釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。