Spring MVC 註解 initMethod 掃包
springMVC詳解以及註解說明
基於註釋(Annotation)的配置有越來越流行的趨勢,Spring 2.5 順應這種趨勢,提供了完全基於註釋配置 Bean、裝配 Bean 的功能,您可以使用基於註釋的 Spring IoC 替換原來基於 XML 的配置。本文通過例項詳細講述了 Spring 2.5 基於註釋 IoC 功能的使用。
概述
註釋配置相對於 XML 配置具有很多的優勢:
· 它可以充分利用 Java 的反射機制獲取類結構資訊,這些資訊可以有效減少配置的工作。如使用 JPA 註釋配置 ORM 對映時,我們就不需要指定 PO 的屬性名、型別等資訊,如果關係表字段和 PO 屬性名、型別都一致,您甚至無需編寫任務屬性對映資訊——因為這些資訊都可以通過 Java 反射機制獲取。
· 註釋和 Java 程式碼位於一個檔案中,而 XML 配置採用獨立的配置檔案,大多數配置資訊在程式開發完成後都不會調整,如果配置資訊和 Java 程式碼放在一起,有助於增強程式的內聚性。而採用獨立的 XML 配置檔案,程式設計師在編寫一個功能時,往往需要在程式檔案和配置檔案中不停切換,這種思維上的不連貫會降低開發效率。
因此在很多情況下,註釋配置比 XML 配置更受歡迎,註釋配置有進一步流行的趨勢。Spring 2.5 的一大增強就是引入了很多註釋類,現在您已經可以使用註釋配置完成大部分 XML 配置的功能。在這篇文章裡,我們將向您講述使用註釋進行 Bean 定義和依賴注入的內容。
Spring2.5
Spring 2.5 提供了 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor和RequiredAnnotationBeanPostProcessor這四個主要的關於Annotation的BeanPostProcessor。
我們可以使用<context:annotation-config /> 來方便地、一次性的宣告者四個BeanPostProcessor。
1.Autowired... 提供對 Spring 特有的 Autowired 和 Qualifier 註釋。
2.CommonAnotation... 用於支援 JSR 250 的註釋
3.Persistence...用於 JPA 的 PersistenceUnit 和PersistenceContext 註釋
4.Required... 用於檢查被 Required 註釋標記的屬性是否被設定
原來我們是怎麼做的
在使用註釋配置之前,先來回顧一下傳統上是如何配置 Bean 並完成 Bean 之間依賴關係的建立。下面是 3 個類,它們分別是 Office、Car 和 Boss,這 3 個類需要在 Spring 容器中配置為 Bean:
Office 僅有一個屬性:
清單 1. Office.java
package com.baobaotao; public class Office { private String officeNo =”001”; //省略 get/setter @Override public String toString() { return "officeNo:" + officeNo; } } |
Car 擁有兩個屬性:
清單 2. Car.java
package com.baobaotao; public class Car { private String brand; private double price; // 省略 get/setter @Override public String toString() { return "brand:" + brand + "," + "price:" + price; } } |
Boss 擁有 Office 和 Car 型別的兩個屬性:
清單 3. Boss.java
package com.baobaotao; public class Boss { private Car car; private Office office; // 省略 get/setter @Override public String toString() { return "car:" + car + "\n" + "office:" + office; } } |
我們在 Spring 容器中將 Office 和 Car 宣告為 Bean,並注入到 BossBean 中:下面是使用傳統 XML 完成這個工作的配置檔案 beans.xml:
清單 4. beans.xml將以上三個類配置成 Bean
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans <bean id="boss" class="com.baobaotao.Boss"> <property name="car" ref="car"/> <property name="office" ref="office" /> </bean> <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="002"/> </bean> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value="紅旗 CA72"/> <property name="price" value="2000"/> </bean> </beans> |
當我們執行以下程式碼時,控制檯將正確打出 boss 的資訊:
清單 5.
測試類:AnnoIoCTest.java
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AnnoIoCTest { public static void main(String[] args) { String[] locations = {"beans.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(locations); Boss boss = (Boss) ctx.getBean("boss"); System.out.println(boss); } } |
這說明 Spring 容器已經正確完成了 Bean 建立和裝配的工作。
使用 @Autowired註釋(按型別匹配)
Spring 2.5 引入了 @Autowired 註釋,它可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作。來看一下使用 @Autowired 進行成員變數自動注入的程式碼:
清單 6.
使用 @Autowired
註釋的 Boss.java
package com.baobaotao; import org.springframework.beans.factory.annotation.Autowired; public class Boss { @Autowired private Car car; @Autowired private Office office; … } |
Spring 通過一個BeanPostProcessor 對 @Autowired 進行解析,所以要讓@Autowired起作用必須事先在 Spring 容器中宣告AutowiredAnnotationBeanPostProcessorBean。
清單 7.
讓 @Autowired
註釋工作起來
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- 該 BeanPostProcessor 將自動起作用,對標註 @Autowired的 Bean進行自動注入 --> <bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor"/> <!-- 移除 boss Bean 的屬性注入配置的資訊 --> <bean id="boss" class="com.baobaotao.Boss"/> <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value="紅旗 CA72"/> <property name="price" value="2000"/> </bean> </beans> |
這樣,當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 註釋時就找到和其匹配(預設按型別匹配)的 Bean,並注入到對應的地方中去。
按照上面的配置,Spring 將直接採用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變數進行自動注入。所以對成員變數使用 @Autowired 後,您大可將它們的 setter方法(setCar() 和 setOffice())從 Boss中刪除。
當然,您也可以通過 @Autowired對方法或建構函式進行標註,來看下面的程式碼:
清單 8.
將 @Autowired
註釋標註在 Setter
方法上
package com.baobaotao; public class Boss { private Car car; private Office office; @Autowired public void setCar(Car car) { this.car = car; } @Autowired public void setOffice(Office office) { this.office = office; } … } |
這時,@Autowired 將查詢被標註的方法的入參型別的 Bean,並呼叫方法自動注入這些 Bean。而下面的使用方法則對建構函式進行標註:
清單 9.
將 @Autowired
注釋標註在建構函式上
package com.baobaotao; public class Boss { private Car car; private Office office; @Autowired public Boss(Car car ,Office office){ this.car = car; this.office = office ; } … } |
由於 Boss() 建構函式有兩個入參,分別是 car 和 office,@Autowired 將分別尋找和它們型別匹配的 Bean,將它們作為 Boss(Car car,Office office) 的入參來建立 Boss Bean。
當候選 Bean數目不為 1 時的應對方法
在預設情況下使用 @Autowired 註釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將丟擲BeanCreationException 異常,並指出必須至少擁有一個匹配的 Bean。我們可以來做一個實驗:
清單 10.
候選 Bean 數目為 0時
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd "> <bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor"/> <bean id="boss" class="com.baobaotao.Boss"/> <!-- 將 office Bean 註釋掉 --> <!-- <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean>--> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value="紅旗 CA72"/> <property name="price" value="2000"/> </bean> </beans> |
由於 office Bean 被註釋掉了,所以 Spring 容器中將沒有型別為 Office 的 Bean 了,而 Boss 的 office 屬性標註了 @Autowired,當啟動 Spring 容器時,異常就產生了。
當不能確定 Spring 容器中一定擁有某個類的 Bean 時,可以在需要自動注入該類 Bean 的地方可以使用@Autowired(required = false),這等於告訴 Spring:在找不到匹配 Bean 時也不報錯。來看一下具體的例子:
清單 11.
使用 @Autowired(required = false)
package com.baobaotao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; public class Boss { private Car car; private Office office; @Autowired public void setCar(Car car) { this.car = car; } @Autowired(required = false) public void setOffice(Office office) { this.office = office; } … } |
當然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發期或測試期碰到(如為了快速啟動 Spring 容器,僅引入一些模組的 Spring 配置檔案),所以@Autowired(required = false) 會很少用到。
和找不到一個型別匹配 Bean 相反的一個錯誤是:如果 Spring 容器中擁有多個候選 Bean,Spring 容器在啟動時也會丟擲BeanCreationException 異常。來看下面的例子:
清單 12.
在 beans.xml
中配置兩個 Office
型別的 Bean
… <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean> <bean id="office2" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean> … |
我們在 Spring 容器中配置了兩個型別為 Office 型別的 Bean,當對 Boss 的 office 成員變數進行自動注入時,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發生了。
Spring 允許我們通過 @Qualifier註釋指定注入 Bean的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:
清單 13.
使用 @Qualifier
註釋指定注入 Bean
的名稱
@Autowired public void setOffice(@Qualifier("office")Office office) { this.office = office; } |
@Qualifier("office")中的office是Bean 的名稱,所以 @Autowired和@Qualifier 結合使用時,自動注入的策略就從 byType 轉變成byName 了。
@Autowired 可以對成員變數、方法以及建構函式進行註釋,而 @Qualifier 的標註物件是成員變數、方法入參、建構函式入參。正是由於註釋物件的不同,所以 Spring 不將 @Autowired 和 @Qualifier 統一成一個註釋類。下面是對成員變數和建構函式入參進行註釋的程式碼:
對成員變數進行註釋:
清單 14.
對成員變數使用 @Qualifier註釋
public class Boss { @Autowired private Car car; @Autowired @Qualifier("office") private Office office; … } |
對建構函式入參進行註釋:
清單 15.
對建構函式變數使用 @Qualifier註釋
public class Boss { private Car car; private Office office; @Autowired public Boss(Car car , @Qualifier("office")Office office){ this.car = car; this.office = office ; } } |
@Qualifier只能和 @Autowired結合使用,是對@Autowired 有益的補充。一般來講,@Qualifier 對方法簽名中入參進行註釋會降低程式碼的可讀性,而對成員變數註釋則相對好一些。
使用 JSR-250的註釋
Spring 不但支援自己定義的 @Autowired 的註釋,還支援幾個由 JSR-250 規範定義的註釋,它們分別是 @Resource、@PostConstruct以及 @PreDestroy。
@Resource
@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 的例子:
清單 16.
使用 @Resource
註釋的 Boss.java
package com.baobaotao; import javax.annotation.Resource; public class Boss { // 自動注入型別為 Car 的 Bean @Resource private Car car; // 自動注入 bean 名稱為 office的 Bean @Resource(name = "office") private Office office; } |
一般情況下,我們無需使用類似於@Resource(type=Car.class) 的註釋方式,因為 Bean 的型別資訊可以通過 Java 反射從程式碼中獲取。
要讓 JSR-250 的註釋生效,除了在 Bean類中標註這些註釋外,還需要在Spring容器中註冊一個負責處理這些註釋的 BeanPostProcessor:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/> |
CommonAnnotationBeanPostProcessor實現了 BeanPostProcessor 介面,它負責掃描使用了 JSR-250 註釋的 Bean,並對它們進行相應的操作。
@PostConstruct 和@PreDestroy
Spring 容器中的 Bean 是有生命週期的,Spring 允許在 Bean 在初始化完成後以及 Bean 銷燬前執行特定的操作,您既可以通過實現InitializingBean/DisposableBean 介面來定製初始化之後 / 銷燬之前的操作方法,也可以通過 <bean>元素的 init-method/destroy-method 屬性指定初始化之後 / 銷燬之前呼叫的操作方法。
JSR-250 為初始化之後/銷燬之前方法的指定定義了兩個註釋類,分別是@PostConstruct 和 @PreDestroy,這兩個註釋只能應用於方法上。標註了@PostConstruct註釋的方法將在類例項化後呼叫,而標註了 @PreDestroy的方法將在類銷燬之前呼叫。
清單 17.
使用 @PostConstruct
和 @PreDestroy
註釋的 Boss.java
package com.baobaotao; import javax.annotation.Resource; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class Boss { @Resource private Car car; @Resource(name = "office") private Office office; @PostConstruct public void postConstruct1(){ System.out.println("postConstruct1"); } @PreDestroy public void preDestroy1(){ System.out.println("preDestroy1"); } … } |
您只需要在方法前標註@PostConstruct 或 @PreDestroy,這些方法就會在 Bean 初始化後或銷燬之前被 Spring 容器執行了。
我們知道,不管是通過實現InitializingBean/DisposableBean 介面,還是通過 <bean> 元素的init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷燬的方法。但是使用@PostConstruct 和 @PreDestroy 註釋卻可以指定多個初始化 / 銷燬方法,那些被標註@PostConstruct 或@PreDestroy 註釋的方法都會在初始化
/ 銷燬時被執行。 *********需要注意的是用了這兩個註解標註的方法是不可以有引數的,否則就會報錯:java.lang.IllegalStateException: Lifecycle method annotation requires a no-arg method *****************************
通過以下的測試程式碼,您將可以看到 Bean 的初始化 / 銷燬方法是如何被執行的:
清單 18.
測試類程式碼
package com.baobaotao; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AnnoIoCTest { public static void main(String[] args) { String[] locations = {"beans.xml"}; ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(locations); Boss boss = (Boss) ctx.getBean("boss"); System.out.println(boss); ctx.destroy();// 關閉 Spring 容器,以觸發 Bean銷燬方法的執行 } } |
這時,您將看到標註了@PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動時,建立 Boss Bean 的時候被觸發執行,而標註了 @PreDestroy 註釋的preDestroy1() 方法將在 Spring 容器關閉前銷燬 Boss Bean 的時候被觸發執行。
使用<context:annotation-config/>簡化配置
Spring 2.1 添加了一個新的 context的 Schema 名稱空間,該名稱空間對註釋驅動、屬性檔案引入、載入期織入等功能提供了便捷的配置。我們知道註釋本身是不會做任何事情的,它僅提供元資料資訊。要使元資料資訊真正起作用,必須讓負責處理這些元資料的處理器工作起來。
而我們前面所介紹的AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor 就是處理這些註釋元資料的處理器。但是直接在 Spring 配置檔案中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的註冊這些BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請看下面的配置:
清單 19.
調整 beans.xml
配置檔案
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean id="boss" class="com.baobaotao.Boss"/> <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value="紅旗 CA72"/> <property name="price" value="2000"/> </bean> </beans> |
<context:annotationconfig/>將隱式地向 Spring容器註冊AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及equiredAnnotationBeanPostProcessor這 4 個BeanPostProcessor。
在配置檔案中使用 context 名稱空間之前,必須在<beans> 元素中宣告 context 名稱空間。
使用 @Component
雖然我們可以通過 @Autowired 或 @Resource 在 Bean 類中使用自動注入功能,但是 Bean 還是在 XML 檔案中通過 <bean>進行定義 —— 也就是說,在 XML 配置檔案中定義 Bean,通過 @Autowired 或 @Resource 為 Bean 的成員變數、方法入參或建構函式入參提供自動注入的功能。能否也通過註釋定義 Bean,從 XML 配置檔案中完全移除Bean 定義的配置呢?答案是肯定的,我們通過Spring 2.5提供的 @Component 註釋就可以達到這個目標了。
下面,我們完全使用註釋定義 Bean 並完成 Bean 之間裝配:
清單 20.
使用 @Component
註釋的 Car.java
package com.baobaotao; import org.springframework.stereotype.Component; @Component public class Car { … } |
僅需要在類定義處,使用 @Component 註釋就可以將一個類定義了 Spring 容器中的 Bean。下面的程式碼將 Office 定義為一個 Bean:
清單 21.
使用 @Component
註釋的 Office.java
package com.baobaotao; import org.springframework.stereotype.Component; @Component public class Office { private String officeNo = "001"; … } |
這樣,我們就可以在 Boss 類中通過 @Autowired 注入前面定義的 Car 和 Office Bean 了。
清單 22.
使用 @Component
註釋的 Boss.java
package com.baobaotao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Component("boss") public class Boss { @Autowired private Car car; @Autowired private Office office; … } |
@Component 有一個可選的入參,用於指定 Bean 的名稱,在 Boss 中,我們就將 Bean 名稱定義為“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。
在使用 @Component 註釋後,Spring容器必須啟用類掃描機制以啟用註釋驅動 Bean定義和註釋驅動Bean 自動注入的策略。Spring 2.5 對context 名稱空間進行了擴充套件,提供了這一功能,請看下面的配置:
清單 23.
簡化版的 beans.xml
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context <context:component-scan base-package="com.baobaotao"/> </beans> |
這裡,所有通過 <bean>元素定義 Bean 的配置內容已經被移除,僅需要新增一行<context:component-scan/> 配置就解決所有問題了——Spring XML 配置檔案得到了極致的簡化(當然配置元資料還是需要的,只不過以註釋形式存在罷了)。<context:component-scan/>的 base-package 屬性指定了需要掃描的類包,類包及其遞迴子包中所有的類都會被處理。
<context:component-scan/>還允許定義過濾器將基包下的某些類納入或排除。Spring 支援以下 4 種類型的過濾方式,通過下表說明:
表 1.
掃描過濾方式
過濾器型別 |
說明 |
註釋 |
假如 com.baobaotao.SomeAnnotation 是一個註釋類,我們可以將使用該註釋的類過濾出來。 |
類名指定 |
通過全限定類名進行過濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。 |
正則表示式 |
通過正則表示式定義過濾的類,如下所示: com\.baobaotao\.Default.* |
AspectJ 表示式 |
通過 AspectJ 表示式定義過濾的類,如下所示: com. baobaotao..*Service+ |
下面是一個簡單的例子:
<context:component-scan base-package="com.baobaotao"> <context:include-filter type="regex" expression="com\.baobaotao\.service\..*"/> <context:exclude-filter type="aspectj" expression="com.baobaotao.util..*"/> </context:component-scan> |
值得注意的是<context:component-scan/> 配置項不但啟用了對類包進行掃描以實施註釋驅動 Bean 定義的功能,同時還啟用了註釋驅動自動注入的功能(即還隱式地在內部註冊了AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor),因此當使用<context:component-scan/>後,就可以將<context:annotation-config/>移除了。
預設情況下通過 @Component 定義的 Bean 都是 singleton 的,如果需要使用其它作用範圍的 Bean,可以通過 @Scope 註釋來達到目標,如以下程式碼所示:
清單 24.
通過 @Scope 指定 Bean的作用範圍
package com.baobaotao; import org.springframework.context.annotation.Scope; … @Scope("prototype") @Component("boss") public class Boss { … } |
這樣,當從 Spring 容器中獲取 boss Bean 時,每次返回的都是新的例項了。
具有特殊語義的註釋
Spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個註釋和 @Component 是等效的,但是從註釋類的命名上,很容易看出這 3 個註釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個註釋和 @Component 相比沒有什麼新意,但 Spring 將在以後的版本中為它們新增特殊的功能。所以,如果 Web 應用程式採用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別採用 @Repository、@Service 和 @Controller 對分層中的類進行註釋,而用 @Component 對那些比較中立的類進行註釋。
註釋配置和 XML配置的適用場合
是否有了這些 IOC 註釋,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的。有以下幾點原因:
· 註釋配置不一定在先天上優於 XML 配置。如果 Bean 的依賴關係是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置資訊不會在部署時發生調整,那麼註釋配置優於 XML 配置;反之如果這種依賴關係會在部署時發生調整,XML 配置顯然又優於註釋配置,因為註釋是對 Java 原始碼的調整,您需要重新改寫原始碼並重新編譯才可以實施調整。
· 如果 Bean 不是自己編寫的類(如 JdbcTemplate、SessionFactoryBean等),註釋配置將無法實施,此時 XML 配置是唯一可用的方式。
· 註釋配置往往是類級別的,而 XML 配置則可以表現得更加靈活。比如相比於 @Transaction事務註釋,使用 aop/tx 名稱空間的事務配置更加靈活和簡單。
所以在實現應用中,我們往往需要同時使用註釋配置和 XML 配置,對於類級別且不會發生變動的配置可以優先考慮註釋配置;而對於那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 建立和 Bean 注入之前將這兩種配置方式的元資訊融合在一起。
小結
Spring 在 2.1 以後對註釋配置提供了強力的支援,註釋配置功能成為 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的註釋配置,可以有效減少配置的工作量,提高程式的內聚性。但是這並不意味著傳統 XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如資料來源、快取池、持久層操作模板類、事務管理等內容的配置上,XML 配置依然擁有不可替代的地位。
Spring2.5 註解介紹(3.0通用)
註解說明
• 註冊註解處理器
• 方式一:bean
<beanclass="org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor"/>
• 方式二: 名稱空間<context:annotation-config/>
<context:annotationconfig /> 將隱式地向Spring 容器註冊AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor 、 PersistenceAnnotationBeanPostProcessor 以及RequiredAnnotationBeanPostProcessor 這4 個BeanPostProcessor 。
• 方式三: 名稱空間<context:component-scan/>
如果要使註解工作,則必須配置component-scan ,實際上不需要再配置annotation-config。
base-package 屬性指定了需要掃描的類包,類包及其遞迴子包中所有的類都會被處理。還允許定義過濾器將基包下的某些類納入或排除。
• Spring 支援以下4 種類型的過濾方式:
• 註解 org.example.SomeAnnotation 將所有使用SomeAnnotation 註解的類過濾出來
• 類名指定 org.example.SomeClass 過濾指定的類
• 正則表示式 com.kedacom.spring.annotation.web..* 通過正則表示式過濾一些類
• AspectJ 表示式 org.example..*Service+ 通過AspectJ 表示式過濾一些類
• 正則表示式的過濾方式舉例:
<context:component-scanbase-package="com.casheen.spring.annotation">
<context:exclude-filtertype="regex"
expression="com.casheen.spring.annotation.web..*"/>
</context:component-scan>
• 註解的過濾方式舉例:
<context:component-scanbase-package="com.netqin" >
<context:include-filtertype="annotation"
expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
啟用Spring MVC 註解
• 啟動SpringMVC 的註解功能,完成請求和註解POJO 的對映
• <beanclass="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
註解介紹
• @Controller
• @Service
• @Autowired
• @RequestMapping
• @RequestParam
• @ModelAttribute
• @Cacheable
• @CacheFlush
• @Resource
• @PostConstruct
• @PreDestroy
• @Repository
• @Component (不推薦使用)
• @Scope
• @SessionAttributes
• @InitBinder
@Component是通用標註,@Controller標註web控制器,@Service標註Servicec層的服務,@Respository標註DAO層的資料訪問
@Controller
• 例如
@Controller
public class SoftCreateController extends SimpleBaseController {}