Spring註解@Component、@Repository、@Service、@Controller區別html
spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個註釋和 @Component 是等效的,可是從註釋類的命名上,很容易看出這 3 個註釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個註釋和 @Component 相比沒有什麼新意,但 Spring 將在之後的版本中爲它們添加特殊的功能。因此,若是Web 應用程序採用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別採用@Repository、@Service 和 @Controller 對分層中的類進行註釋,而用 @Component 對那些比較中立的類進行註釋。
在一個稍大的項目中,一般會有上百個組件,若是這些組件採用xml的bean定義來配置,顯然會增長配置文件的體積,查找以及維護起來也不太方便。 Spring2.5爲咱們引入了組件自動掃描機制,他能夠在類路徑底下尋找標註了@Component,@Service,@Controller,@Repository註解的類,並把這些類歸入進spring容器中管理。它的做用和在xml文件中使用bean節點配置組件時同樣的。要使用自動掃描機制,咱們須要打開如下配置信息:
Java代碼
1. <?xml version="1.0" encoding="UTF-8" ?> <beansxmlns="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"
2. >
3.
4. <context:component-scan base-package=」com.eric.spring」>
5. </beans>
6. 其中base-package爲須要掃描的包(含全部子包) @Service用於標註業務層組件,@Controller用於標註控制層組件(如struts中的action),@Repository用於標註數據訪問組件,即DAO組件,而@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。
7. @Service public class VentorServiceImpl implements iVentorService{
8. } @Repository public class VentorDaoImpl implements iVentorDao {
9. } getBean的默認名稱是類名(頭字母小寫),若是想自定義,能夠@Service(「aaaaa」)這樣來指定,這種bean默認是單例的,若是想改變,可使用@Service(「beanName」)@Scope(「prototype」)來改變。可使用如下方式指定初始化方法和銷燬方法(方法名任意): @PostConstructpublic void init() {
10. }
11. @PreDestroy public void destory() {
12. }
注入方式:
把DAO實現類注入到service實現類中,把service的接口(注意不要是service的實現類)注入到action中,注
入時不要new 這個注入的類,由於spring會自動注入,若是手動再new的話會出現錯誤,而後屬性加上
@Autowired後不須要getter()和setter()方法,Spring也會自動注入。至於更具體的內容,等對注入的方式更
加熟練後會作個完整的例子上來。
註解:
在 spring的配置文件裏面只須要加上<context:annotation-config/>和<context:component-scanbase-package="須要實現注入的類所在包"/>,可使用base-package="*"表示所有的類。
<context:component-scan base-package=」com.eric.spring」>
其中base-package爲須要掃描的包(含全部子包)
在接口前面標上@Autowired和@Qualifier註釋使得接口能夠被容器注入,當接口存在兩個實現類的時候必須指定其中一個來注入,使用實現類首字母小寫的字符串來注入,如:
@Autowired
@Qualifier("chinese")
private Man man;
不然能夠省略,只寫@Autowired 。
@Service服務層組件,用於標註業務層組件,表示定義一個bean,自動根據bean的類名實例化一個首寫字母爲小寫的bean,例如Chinese實例化爲chinese,若是須要本身更名字則:@Service("你本身改的bean名")。
@Controller用於標註控制層組件(如struts中的action)
@Repository持久層組件,用於標註數據訪問組件,即DAO組件
@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。
@Service
public class VentorServiceImpl implements iVentorService {
}
@Repository
public class VentorDaoImpl implements iVentorDao {
}
getBean 的默認名稱是類名(頭字母小寫),若是想自定義,能夠@Service(「aaaaa」) 這樣來指定,這種
bean默認是單例的,若是想改變,可使用@Service(「beanName」)@Scope(「prototype」)來改變。
可使用如下方式指定初始化方法和銷燬方法(方法名任意):
@PostConstruct
public void init() {
}
@PreDestroy
public void destory() {
} java
BY ETHAN ON 2011年 06 月 02 日 IN JAVA程序員
Spring不但支持本身定義的@Autowired註解,還支持幾個由JSR-250規範定義的註解,它們分別是@Resource、@PostConstruct以及@PreDestroy。
@Resource的做用至關於@Autowired,只不過@Autowired按byType自動注入,而@Resource默認按 byName自動注入罷了。@Resource有兩個屬性是比較重要的,分是name和type,Spring將@Resource註解的name屬性解析爲bean的名字,而type屬性則解析爲bean的類型。因此若是使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。若是既不指定name也不指定type屬性,這時將經過反射機制使用byName自動注入策略。
@Resource裝配順序
1. 若是同時指定了name和type,則從Spring上下文中找到惟一匹配的bean進行裝配,找不到則拋出異常
2. 若是指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
3. 若是指定了type,則從上下文中找到類型匹配的惟一bean進行裝配,找不到或者找到多個,都會拋出異常
4. 若是既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;若是沒有匹配,則回退爲一個原始類型進行匹配,若是匹配則自動裝配;正則表達式
@Autowired 與@Resource的區別:spring
一、 @Autowired與@Resource均可以用來裝配bean.均可以寫在字段上,或寫在setter方法上。express
二、 @Autowired默認按類型裝配(這個註解是屬業spring的),默認狀況下必需要求依賴對象必須存在,若是要容許null值,能夠設置它的required屬性爲false,如:@Autowired(required=false),若是咱們想使用名稱裝配能夠結合@Qualifier註解進行使用,以下:緩存
|
|
|
|
三、@Resource(這個註解屬於J2EE的),默認安裝名稱進行裝配,名稱能夠經過name屬性進行指定,若是沒有指定name屬性,當註解寫在字段上時,默認取字段名進行安裝名稱查找,若是註解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。可是須要注意的是,若是name屬性一旦指定,就只會按照名稱進行裝配。
|
|
|
|
|
推薦使用:@Resource註解在字段上,這樣就不用寫setter方法了,而且這個註解是屬於J2EE的,減小了與spring的耦合。這樣代碼看起就比較優雅。
1. 使用Spring2.5的Autowired實現註釋型的IOC
2.
3. 本文地址:http://qzone.qq.com/blog/55357655-1232078233
4.
5. 使用Spring2.5的新特性——Autowired能夠實現快速的自動注入,而無需在xml文檔裏面添加bean的聲明,大大減小了xml文檔的維護。(偶喜歡這個功能,由於偶對xml不感冒)。 如下是一個例子:
6. 先編寫接口Man:
7. public interface Man {
8. public String sayHello();
9. }
10. 而後寫Man的實現類Chinese和American:
11. @Service
12. public class Chinese implements Man{
13. public String sayHello() {
14. return "I am Chinese!";
15. }
16. }
17.
18. @Service
19. public class American implements Man{
20. public String sayHello() {
21. return "I am American!";
22. }
23. }
24.
25. @Service註釋表示定義一個bean,自動根據bean的類名實例化一個首寫字母爲小寫的bean,例如Chinese實例化爲chinese,American實例化爲american,若是須要本身更名字則:@Service("你本身改的bean名")。
26.
27. beans.xml
28. <?xml version="1.0" encoding="UTF-8"?>
29. <beans xmlns="http://www.springframework.org/schema/beans"
30. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
31. xmlns:context="http://www.springframework.org/schema/context"
32. xsi:schemaLocation="http://www.springframework.org/schema/beans
33. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
34. http://www.springframework.org/schema/context
35. http://www.springframework.org/schema/context/spring-context-2.5.xsd">
36. <context:annotation-config/>
37. <context:component-scan base-package="testspring.main"/>
38. </beans>
39. 在spring的配置文件裏面只須要加上<context:annotation-config/>和<context:component-scan base-package="須要實現注入的類所在包"/>,可使用base-package="*"表示所有的類。
40.
41. 編寫主類測試:
42. @Service
43. public class Main {
44. @Autowired
45. @Qualifier("chinese")
46. private Man man;
47.
48. public static void main(String[] args) {
49. // TODO code application logic here
50. ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
51. Main main = (Main) ctx.getBean("main");
52. System.out.println(main.getMan().sayHello());
53. }
54.
55. public Man getMan() {
56. return man;
57. }
58. }
59.
60. 在Man接口前面標上@Autowired和@Qualifier註釋使得Man接口能夠被容器注入,當Man接口存在兩個實現類的時候必須指定其中一個來注入,使用實現類首字母小寫的字符串來注入。不然能夠省略,只寫@Autowired
61.
62. **********************
63. 使用 Spring 2.5 註釋驅動的 IoC 功能
64. 發表於08-03-04 20:38 | 閱讀 1285 | 評分 (暫無)
65. 概述
66.
67. 註釋配置相對於 XML 配置具備不少的優點:
68.
69. 它能夠充分利用 Java 的反射機制獲取類結構信息,這些信息能夠有效減小配置的工做。如使用 JPA 註釋配置 ORM 映射時,咱們就不須要指定 PO 的屬性名、類型等信息,若是關係表字段和 PO 屬性名、類型都一致,您甚至無需編寫任務屬性映射信息——由於這些信息均可以經過 Java 反射機制獲取。
70. 註釋和 Java 代碼位於一個文件中,而 XML 配置採用獨立的配置文件,大多數配置信息在程序開發完成後都不會調整,若是配置信息和 Java 代碼放在一塊兒,有助於加強程序的內聚性。而採用獨立的 XML 配置文件,程序員在編寫一個功能時,每每須要在程序文件和配置文件中不停切換,這種思惟上的不連貫會下降開發效率。
71. 所以在不少狀況下,註釋配置比 XML 配置更受歡迎,註釋配置有進一步流行的趨勢。Spring 2.5 的一大加強就是引入了不少註釋類,如今您已經可使用註釋配置完成大部分 XML 配置的功能。在這篇文章裏,咱們將向您講述使用註釋進行 Bean 定義和依賴注入的內容。
72.
73.
74. 原來咱們是怎麼作的
75.
76. 在使用註釋配置以前,先來回顧一下傳統上是如何配置 Bean 並完成 Bean 之間依賴關係的創建。下面是 3 個類,它們分別是 Office、Car 和 Boss,這 3 個類須要在 Spring 容器中配置爲 Bean:
77.
78. Office 僅有一個屬性:
79.
80.
81. 清單 1. Office.java
82.
83. package com.baobaotao;
84. public class Office {
85. private String officeNo =」001」;
86.
87. //省略 get/setter
88.
89. @Override
90. public String toString() {
91. return "officeNo:" + officeNo;
92. }
93. }
94.
95.
96.
97. Car 擁有兩個屬性:
98.
99.
100. 清單 2. Car.java
101.
102. package com.baobaotao;
103.
104. public class Car {
105. private String brand;
106. private double price;
107.
108. // 省略 get/setter
109.
110. @Override
111. public String toString() {
112. return "brand:" + brand + "," + "price:" + price;
113. }
114. }
115.
116.
117.
118. Boss 擁有 Office 和 Car 類型的兩個屬性:
119.
120.
121. 清單 3. Boss.java
122.
123. package com.baobaotao;
124.
125. public class Boss {
126. private Car car;
127. private Office office;
128.
129. // 省略 get/setter
130.
131. @Override
132. public String toString() {
133. return "car:" + car + "\n" + "office:" + office;
134. }
135. }
136.
137.
138.
139. 咱們在 Spring 容器中將 Office 和 Car 聲明爲 Bean,並注入到 Boss Bean 中:下面是使用傳統 XML 完成這個工做的配置文件 beans.xml:
140.
141.
142. 清單 4. beans.xml 將以上三個類配置成 Bean
143.
144. <?xml version="1.0" encoding="UTF-8" ?>
145. <beans xmlns="http://www.springframework.org/schema/beans"
146. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
147. xsi:schemaLocation="http://www.springframework.org/schema/beans
148. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
149. <bean id="boss" class="com.baobaotao.Boss">
150. <property name="car" ref="car"/>
151. <property name="office" ref="office" />
152. </bean>
153. <bean id="office" class="com.baobaotao.Office">
154. <property name="officeNo" value="002"/>
155. </bean>
156. <bean id="car" class="com.baobaotao.Car" scope="singleton">
157. <property name="brand" value=" 紅旗 CA72"/>
158. <property name="price" value="2000"/>
159. </bean>
160. </beans>
161.
162.
163.
164. 當咱們運行如下代碼時,控制檯將正確打出 boss 的信息:
165.
166.
167. 清單 5. 測試類:AnnoIoCTest.java
168.
169. import org.springframework.context.ApplicationContext;
170. import org.springframework.context.support.ClassPathXmlApplicationContext;
171. public class AnnoIoCTest {
172.
173. public static void main(String[] args) {
174. String[] locations = {"beans.xml"};
175. ApplicationContext ctx =
176. new ClassPathXmlApplicationContext(locations);
177. Boss boss = (Boss) ctx.getBean("boss");
178. System.out.println(boss);
179. }
180. }
181.
182.
183.
184. 這說明 Spring 容器已經正確完成了 Bean 建立和裝配的工做。
185.
186.
187. 使用 @Autowired 註釋
188.
189. Spring 2.5 引入了 @Autowired 註釋,它能夠對類成員變量、方法及構造函數進行標註,完成自動裝配的工做。來看一下使用 @Autowired 進行成員變量自動注入的代碼:
190.
191.
192. 清單 6. 使用 @Autowired 註釋的 Boss.java
193.
194. package com.baobaotao;
195. import org.springframework.beans.factory.annotation.Autowired;
196.
197. public class Boss {
198.
199. @Autowired
200. private Car car;
201.
202. @Autowired
203. private Office office;
204.
205. …
206. }
207.
208.
209.
210. Spring 經過一個 BeanPostProcessor 對 @Autowired 進行解析,因此要讓 @Autowired 起做用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。
211.
212.
213. 清單 7. 讓 @Autowired 註釋工做起來
214.
215. <?xml version="1.0" encoding="UTF-8" ?>
216. <beans xmlns="http://www.springframework.org/schema/beans"
217. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
218. xsi:schemaLocation="http://www.springframework.org/schema/beans
219. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
220.
221. <!-- 該 BeanPostProcessor 將自動起做用,對標註 @Autowired 的 Bean 進行自動注入 -->
222. <bean class="org.springframework.beans.factory.annotation.
223. AutowiredAnnotationBeanPostProcessor"/>
224.
225. <!-- 移除 boss Bean 的屬性注入配置的信息 -->
226. <bean id="boss" class="com.baobaotao.Boss"/>
227.
228. <bean id="office" class="com.baobaotao.Office">
229. <property name="officeNo" value="001"/>
230. </bean>
231. <bean id="car" class="com.baobaotao.Car" scope="singleton">
232. <property name="brand" value=" 紅旗 CA72"/>
233. <property name="price" value="2000"/>
234. </bean>
235. </beans>
236.
237.
238.
239. 這樣,當 Spring 容器啓動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中全部 Bean,當發現 Bean 中擁有 @Autowired 註釋時就找到和其匹配(默認按類型匹配)的 Bean,並注入到對應的地方中去。
240.
241. 按照上面的配置,Spring 將直接採用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變量進行自動注入。因此對成員變量使用 @Autowired 後,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。
242.
243. 固然,您也能夠經過 @Autowired 對方法或構造函數進行標註,來看下面的代碼:
244.
245.
246. 清單 8. 將 @Autowired 註釋標註在 Setter 方法上
247.
248. package com.baobaotao;
249.
250. public class Boss {
251. private Car car;
252. private Office office;
253.
254. @Autowired
255. public void setCar(Car car) {
256. this.car = car;
257. }
258.
259. @Autowired
260. public void setOffice(Office office) {
261. this.office = office;
262. }
263. …
264. }
265.
266.
267.
268. 這時,@Autowired 將查找被標註的方法的入參類型的 Bean,並調用方法自動注入這些 Bean。而下面的使用方法則對構造函數進行標註:
269.
270.
271. 清單 9. 將 @Autowired 註釋標註在構造函數上
272.
273. package com.baobaotao;
274.
275. public class Boss {
276. private Car car;
277. private Office office;
278.
279. @Autowired
280. public Boss(Car car ,Office office){
281. this.car = car;
282. this.office = office ;
283. }
284.
285. …
286. }
287.
288.
289.
290. 因爲 Boss() 構造函數有兩個入參,分別是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們做爲 Boss(Car car ,Office office) 的入參來建立 Boss Bean。
291.
292.
293. 當候選 Bean 數目不爲 1 時的應對方法
294.
295. 在默認狀況下使用 @Autowired 註釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出 BeanCreationException 異常,並指出必須至少擁有一個匹配的 Bean。咱們能夠來作一個實驗:
296.
297.
298. 清單 10. 候選 Bean 數目爲 0 時
299.
300. <?xml version="1.0" encoding="UTF-8" ?>
301. <beans xmlns="http://www.springframework.org/schema/beans"
302. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
303. xsi:schemaLocation="http://www.springframework.org/schema/beans
304. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ">
305.
306. <bean class="org.springframework.beans.factory.annotation.
307. AutowiredAnnotationBeanPostProcessor"/>
308.
309. <bean id="boss" class="com.baobaotao.Boss"/>
310.
311. <!-- 將 office Bean 註釋掉 -->
312. <!-- <bean id="office" class="com.baobaotao.Office">
313. <property name="officeNo" value="001"/>
314. </bean>-->
315.
316. <bean id="car" class="com.baobaotao.Car" scope="singleton">
317. <property name="brand" value=" 紅旗 CA72"/>
318. <property name="price" value="2000"/>
319. </bean>
320. </beans>
321.
322.
323.
324. 因爲 office Bean 被註釋掉了,因此 Spring 容器中將沒有類型爲 Office 的 Bean 了,而 Boss 的 office 屬性標註了 @Autowired,當啓動 Spring 容器時,異常就產生了。
325.
326. 當不能肯定 Spring 容器中必定擁有某個類的 Bean 時,能夠在須要自動注入該類 Bean 的地方可使用 @Autowired(required = false),這等於告訴 Spring:在找不到匹配 Bean 時也不報錯。來看一下具體的例子:
327.
328.
329. 清單 11. 使用 @Autowired(required = false)
330.
331. package com.baobaotao;
332.
333. import org.springframework.beans.factory.annotation.Autowired;
334. import org.springframework.beans.factory.annotation.Required;
335.
336. public class Boss {
337.
338. private Car car;
339. private Office office;
340.
341. @Autowired
342. public void setCar(Car car) {
343. this.car = car;
344. }
345. @Autowired(required = false)
346. public void setOffice(Office office) {
347. this.office = office;
348. }
349. …
350. }
351.
352.
353.
354. 固然,通常狀況下,使用 @Autowired 的地方都是須要注入 Bean 的,使用了自動注入而又容許不注入的狀況通常僅會在開發期或測試期碰到(如爲了快速啓動 Spring 容器,僅引入一些模塊的 Spring 配置文件),因此 @Autowired(required = false) 會不多用到。
355.
356. 和找不到一個類型匹配 Bean 相反的一個錯誤是:若是 Spring 容器中擁有多個候選 Bean,Spring 容器在啓動時也會拋出 BeanCreationException 異常。來看下面的例子:
357.
358.
359. 清單 12. 在 beans.xml 中配置兩個 Office 類型的 Bean
360.
361. …
362. <bean id="office" class="com.baobaotao.Office">
363. <property name="officeNo" value="001"/>
364. </bean>
365. <bean id="office2" class="com.baobaotao.Office">
366. <property name="officeNo" value="001"/>
367. </bean>
368. …
369.
370.
371.
372. 咱們在 Spring 容器中配置了兩個類型爲 Office 類型的 Bean,當對 Boss 的 office 成員變量進行自動注入時,Spring 容器將沒法肯定到底要用哪個 Bean,所以異常發生了。
373.
374. Spring 容許咱們經過 @Qualifier 註釋指定注入 Bean 的名稱,這樣歧義就消除了,能夠經過下面的方法解決異常:
375.
376.
377. 清單 13. 使用 @Qualifier 註釋指定注入 Bean 的名稱
378.
379. @Autowired
380. public void setOffice(@Qualifier("office")Office office) {
381. this.office = office;
382. }
383.
384.
385.
386. @Qualifier("office") 中的 office 是 Bean 的名稱,因此 @Autowired 和 @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired 能夠對成員變量、方法以及構造函數進行註釋,而 @Qualifier 的標註對象是成員變量、方法入參、構造函數入參。正是因爲註釋對象的不一樣,因此 Spring 不將 @Autowired 和 @Qualifier 統一成一個註釋類。下面是對成員變量和構造函數入參進行註釋的代碼:
387.
388. 對成員變量進行註釋:
389.
390.
391. 清單 14. 對成員變量使用 @Qualifier 註釋
392.
393. public class Boss {
394. @Autowired
395. private Car car;
396.
397. @Autowired
398. @Qualifier("office")
399. private Office office;
400. …
401. }
402.
403.
404.
405. 對構造函數入參進行註釋:
406.
407.
408. 清單 15. 對構造函數變量使用 @Qualifier 註釋
409.
410. public class Boss {
411. private Car car;
412. private Office office;
413.
414. @Autowired
415. public Boss(Car car , @Qualifier("office")Office office){
416. this.car = car;
417. this.office = office ;
418. }
419. }
420.
421.
422.
423. @Qualifier 只能和 @Autowired 結合使用,是對 @Autowired 有益的補充。通常來說,@Qualifier 對方法簽名中入參進行註釋會下降代碼的可讀性,而對成員變量註釋則相對好一些。
424.
425.
426.
427. 使用 JSR-250 的註釋
428.
429. Spring 不但支持本身定義的 @Autowired 的註釋,還支持幾個由 JSR-250 規範定義的註釋,它們分別是 @Resource、@PostConstruct 以及 @PreDestroy。
430.
431. @Resource
432.
433. @Resource 的做用至關於 @Autowired,只不過 @Autowired 按 byType 自動注入,面 @Resource 默認按 byName 自動注入罷了。@Resource 有兩個屬性是比較重要的,分別是 name 和 type,Spring 將 @Resource 註釋的 name 屬性解析爲 Bean 的名字,而 type 屬性則解析爲 Bean 的類型。因此若是使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。若是既不指定 name 也不指定 type 屬性,這時將經過反射機制使用 byName 自動注入策略。
434.
435. Resource 註釋類位於 Spring 發佈包的 lib/j2ee/common-annotations.jar 類包中,所以在使用以前必須將其加入到項目的類庫中。來看一個使用 @Resource 的例子:
436.
437.
438. 清單 16. 使用 @Resource 註釋的 Boss.java
439.
440. package com.baobaotao;
441.
442. import javax.annotation.Resource;
443.
444. public class Boss {
445. // 自動注入類型爲 Car 的 Bean
446. @Resource
447. private Car car;
448.
449. // 自動注入 bean 名稱爲 office 的 Bean
450. @Resource(name = "office")
451. private Office office;
452. }
453.
454.
455.
456. 通常狀況下,咱們無需使用相似於 @Resource(type=Car.class) 的註釋方式,由於 Bean 的類型信息能夠經過 Java 反射從代碼中獲取。
457.
458. 要讓 JSR-250 的註釋生效,除了在 Bean 類中標註這些註釋外,還須要在 Spring 容器中註冊一個負責處理這些註釋的 BeanPostProcessor:
459.
460. <bean
461. class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
462.
463.
464.
465. CommonAnnotationBeanPostProcessor 實現了 BeanPostProcessor 接口,它負責掃描使用了 JSR-250 註釋的 Bean,並對它們進行相應的操做。
466.
467. @PostConstruct 和 @PreDestroy
468.
469. Spring 容器中的 Bean 是有生命週期的,Spring 容許在 Bean 在初始化完成後以及 Bean 銷燬前執行特定的操做,您既能夠經過實現 InitializingBean/DisposableBean 接口來定製初始化以後 / 銷燬以前的操做方法,也能夠經過 <bean> 元素的 init-method/destroy-method 屬性指定初始化以後 / 銷燬以前調用的操做方法。關於 Spring 的生命週期,筆者在《精通 Spring 2.x—企業應用開發精解》第 3 章進行了詳細的描述,有興趣的讀者能夠查閱。
470.
471. JSR-250 爲初始化以後/銷燬以前方法的指定定義了兩個註釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個註釋只能應用於方法上。標註了 @PostConstruct 註釋的方法將在類實例化後調用,而標註了 @PreDestroy 的方法將在類銷燬以前調用。
472.
473.
474. 清單 17. 使用 @PostConstruct 和 @PreDestroy 註釋的 Boss.java
475.
476. package com.baobaotao;
477.
478. import javax.annotation.Resource;
479. import javax.annotation.PostConstruct;
480. import javax.annotation.PreDestroy;
481.
482. public class Boss {
483. @Resource
484. private Car car;
485.
486. @Resource(name = "office")
487. private Office office;
488.
489. @PostConstruct
490. public void postConstruct1(){
491. System.out.println("postConstruct1");
492. }
493.
494. @PreDestroy
495. public void preDestroy1(){
496. System.out.println("preDestroy1");
497. }
498. …
499. }
500.
501.
502.
503. 您只須要在方法前標註 @PostConstruct 或 @PreDestroy,這些方法就會在 Bean 初始化後或銷燬以前被 Spring 容器執行了。
504.
505. 咱們知道,無論是經過實現 InitializingBean/DisposableBean 接口,仍是經過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能爲 Bean 指定一個初始化 / 銷燬的方法。可是使用 @PostConstruct 和 @PreDestroy 註釋卻能夠指定多個初始化 / 銷燬方法,那些被標註 @PostConstruct 或 @PreDestroy 註釋的方法都會在初始化 / 銷燬時被執行。
506.
507. 經過如下的測試代碼,您將能夠看到 Bean 的初始化 / 銷燬方法是如何被執行的:
508.
509.
510. 清單 18. 測試類代碼
511.
512. package com.baobaotao;
513.
514. import org.springframework.context.support.ClassPathXmlApplicationContext;
515.
516. public class AnnoIoCTest {
517.
518. public static void main(String[] args) {
519. String[] locations = {"beans.xml"};
520. ClassPathXmlApplicationContext ctx =
521. new ClassPathXmlApplicationContext(locations);
522. Boss boss = (Boss) ctx.getBean("boss");
523. System.out.println(boss);
524. ctx.destroy();// 關閉 Spring 容器,以觸發 Bean 銷燬方法的執行
525. }
526. }
527.
528.
529.
530. 這時,您將看到標註了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啓動時,建立 Boss Bean 的時候被觸發執行,而標註了 @PreDestroy 註釋的 preDestroy1() 方法將在 Spring 容器關閉前銷燬 Boss Bean 的時候被觸發執行。
531.
532.
533. 使用 <context:annotation-config/> 簡化配置
534.
535. Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對註釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。咱們知道註釋自己是不會作任何事情的,它僅提供元數據信息。要使元數據信息真正起做用,必須讓負責處理這些元數據的處理器工做起來。
536.
537. 而咱們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些註釋元數據的處理器。可是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 爲咱們提供了一種方便的註冊這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請看下面的配置:
538.
539.
540. 清單 19. 調整 beans.xml 配置文件
541.
542. <?xml version="1.0" encoding="UTF-8" ?>
543. <beans xmlns="http://www.springframework.org/schema/beans"
544. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
545. xmlns:context="http://www.springframework.org/schema/context"
546. xsi:schemaLocation="http://www.springframework.org/schema/beans
547. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
548. http://www.springframework.org/schema/context
549. http://www.springframework.org/schema/context/spring-context-2.5.xsd">
550.
551. <context:annotation-config/>
552.
553. <bean id="boss" class="com.baobaotao.Boss"/>
554. <bean id="office" class="com.baobaotao.Office">
555. <property name="officeNo" value="001"/>
556. </bean>
557. <bean id="car" class="com.baobaotao.Car" scope="singleton">
558. <property name="brand" value=" 紅旗 CA72"/>
559. <property name="price" value="2000"/>
560. </bean>
561. </beans>
562.
563.
564.
565. <context:annotationconfig/> 將隱式地向 Spring 容器註冊 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。
566.
567. 在配置文件中使用 context 命名空間以前,必須在 <beans> 元素中聲明 context 命名空間。
568.
569.
570. 使用 @Component
571.
572. 雖然咱們能夠經過 @Autowired 或 @Resource 在 Bean 類中使用自動注入功能,可是 Bean 仍是在 XML 文件中經過 <bean> 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,經過 @Autowired 或 @Resource 爲 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。可否也經過註釋定義 Bean,從 XML 配置文件中徹底移除 Bean 定義的配置呢?答案是確定的,咱們經過 Spring 2.5 提供的 @Component 註釋就能夠達到這個目標了。
573.
574. 下面,咱們徹底使用註釋定義 Bean 並完成 Bean 之間裝配:
575.
576.
577. 清單 20. 使用 @Component 註釋的 Car.java
578.
579. package com.baobaotao;
580.
581. import org.springframework.stereotype.Component;
582.
583. @Component
584. public class Car {
585. …
586. }
587.
588.
589.
590. 僅須要在類定義處,使用 @Component 註釋就能夠將一個類定義了 Spring 容器中的 Bean。下面的代碼將 Office 定義爲一個 Bean:
591.
592.
593. 清單 21. 使用 @Component 註釋的 Office.java
594.
595. package com.baobaotao;
596.
597. import org.springframework.stereotype.Component;
598.
599. @Component
600. public class Office {
601. private String officeNo = "001";
602. …
603. }
604.
605.
606.
607. 這樣,咱們就能夠在 Boss 類中經過 @Autowired 注入前面定義的 Car 和 Office Bean 了。
608.
609.
610. 清單 22. 使用 @Component 註釋的 Boss.java
611.
612. package com.baobaotao;
613.
614. import org.springframework.beans.factory.annotation.Autowired;
615. import org.springframework.beans.factory.annotation.Required;
616. import org.springframework.beans.factory.annotation.Qualifier;
617. import org.springframework.stereotype.Component;
618.
619. @Component("boss")
620. public class Boss {
621. @Autowired
622. private Car car;
623.
624. @Autowired
625. private Office office;
626. …
627. }
628.
629.
630.
631. @Component 有一個可選的入參,用於指定 Bean 的名稱,在 Boss 中,咱們就將 Bean 名稱定義爲「boss」。通常狀況下,Bean 都是 singleton 的,須要注入 Bean 的地方僅須要經過 byType 策略就能夠自動注入了,因此大可沒必要指定 Bean 的名稱。
632.
633. 在使用 @Component 註釋後,Spring 容器必須啓用類掃描機制以啓用註釋驅動 Bean 定義和註釋驅動 Bean 自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置:
634.
635.
636. 清單 23. 簡化版的 beans.xml
637.
638. <?xml version="1.0" encoding="UTF-8" ?>
639. <beans xmlns="http://www.springframework.org/schema/beans"
640. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
641. xmlns:context="http://www.springframework.org/schema/context"
642. xsi:schemaLocation="http://www.springframework.org/schema/beans
643. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
644. http://www.springframework.org/schema/context
645. http://www.springframework.org/schema/context/spring-context-2.5.xsd">
646. <context:component-scan base-package="com.baobaotao"/>
647. </beans>
648.
649.
650.
651. 這裏,全部經過 <bean> 元素定義 Bean 的配置內容已經被移除,僅須要添加一行 <context:component-scan/> 配置就解決全部問題了——Spring XML 配置文件獲得了極致的簡化(固然配置元數據仍是須要的,只不過以註釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了須要掃描的類包,類包及其遞歸子包中全部的類都會被處理。
652.
653. <context:component-scan/> 還容許定義過濾器將基包下的某些類歸入或排除。Spring 支持如下 4 種類型的過濾方式,經過下表說明:
654.
655.
656. 表 1. 掃描過濾方式
657. 過濾器類型 說明
658. 註釋 假如 com.baobaotao.SomeAnnotation 是一個註釋類,咱們能夠將使用該註釋的類過濾出來。
659. 類名指定 經過全限定類名進行過濾,如您能夠指定將 com.baobaotao.Boss 歸入掃描,而將 com.baobaotao.Car 排除在外。
660. 正則表達式 經過正則表達式定義過濾的類,以下所示: com\.baobaotao\.Default.*
661. AspectJ 表達式 經過 AspectJ 表達式定義過濾的類,以下所示: com. baobaotao..*Service+
662.
663. 下面是一個簡單的例子:
664.
665. <context:component-scan base-package="com.baobaotao">
666. <context:include-filter type="regex"
667. expression="com\.baobaotao\.service\..*"/>
668. <context:exclude-filter type="aspectj"
669. expression="com.baobaotao.util..*"/>
670. </context:component-scan>
671.
672.
673.
674. 值得注意的是 <context:component-scan/> 配置項不但啓用了對類包進行掃描以實施註釋驅動 Bean 定義的功能,同時還啓用了註釋驅動自動注入的功能(即還隱式地在內部註冊了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),所以當使用 <context:component-scan/> 後,就能夠將 <context:annotation-config/> 移除了。
675.
676. 默認狀況下經過 @Component 定義的 Bean 都是 singleton 的,若是須要使用其它做用範圍的 Bean,能夠經過 @Scope 註釋來達到目標,如如下代碼所示:
677.
678.
679. 清單 24. 經過 @Scope 指定 Bean 的做用範圍
680.
681. package com.baobaotao;
682. import org.springframework.context.annotation.Scope;
683. …
684. @Scope("prototype")
685. @Component("boss")
686. public class Boss {
687. …
688. }
689.
690.
691. 這樣,當從 Spring 容器中獲取 boss Bean 時,每次返回的都是新的實例了。
692.
693.
694. 採用具備特殊語義的註釋
695.
696. Spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個註釋和 @Component 是等效的,可是從註釋類的命名上,很容易看出這 3 個註釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個註釋和 @Component 相比沒有什麼新意,但 Spring 將在之後的版本中爲它們添加特殊的功能。因此,若是 Web 應用程序採用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別採用 @Repository、@Service 和 @Controller 對分層中的類進行註釋,而用 @Component 對那些比較中立的類進行註釋。
697.
698.
699.
700. 註釋配置和 XML 配置的適用場合
701.
702. 是否有了這些 IOC 註釋,咱們就能夠徹底摒除原來 XML 配置的方式呢?答案是否認的。有如下幾點緣由:
703.
704. 註釋配置不必定在先天上優於 XML 配置。若是 Bean 的依賴關係是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那麼註釋配置優於 XML 配置;反之若是這種依賴關係會在部署時發生調整,XML 配置顯然又優於註釋配置,由於註釋是對 Java 源代碼的調整,您須要從新改寫源代碼並從新編譯才能夠實施調整。
705. 若是 Bean 不是本身編寫的類(如 JdbcTemplate、SessionFactoryBean 等),註釋配置將沒法實施,此時 XML 配置是惟一可用的方式。
706. 註釋配置每每是類級別的,而 XML 配置則能夠表現得更加靈活。好比相比於 @Transaction 事務註釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。
707. 因此在實現應用中,咱們每每須要同時使用註釋配置和 XML 配置,對於類級別且不會發生變更的配置能夠優先考慮註釋配置;而對於那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 建立和 Bean 注入以前將這兩種配置方式的元信息融合在一塊兒。
708.
709.
710. 小結
711.
712. Spring 在 2.1 之後對註釋配置提供了強力的支持,註釋配置功能成爲 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的註釋配置,能夠有效減小配置的工做量,提升程序的內聚性。可是這並不意味着傳統 XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如數據源、緩存池、持久層操做模板類、事務管理等內容的配置上,XML 配置依然擁有不可替代的地位。