概述
創(chuàng)新互聯(lián)建站主營(yíng)介休網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都App制作,介休h5小程序制作搭建,介休網(wǎng)站營(yíng)銷推廣歡迎介休等地區(qū)企業(yè)咨詢
注釋配置相對(duì)于 XML 配置具有很多的優(yōu)勢(shì):
因此在很多情況下,注釋配置比 XML 配置更受歡迎,注釋配置有進(jìn)一步流行的趨勢(shì)。Spring 2.5 的一大增強(qiáng)就是引入了很多注釋類,現(xiàn)在您已經(jīng)可以使用注釋配置完成大部分 XML 配置的功能。在這篇文章里,我們將向您講述使用注釋進(jìn)行 Bean 定義和依賴注入的內(nèi)容。
原來我們是怎么做的
在使用注釋配置之前,先來回顧一下傳統(tǒng)上是如何配置 Bean 并完成 Bean 之間依賴關(guān)系的建立。下面是 3 個(gè)類,它們分別是 Office、Car 和 Boss,這 3 個(gè)類需要在 Spring 容器中配置為 Bean:
Office 僅有一個(gè)屬性:
package com.baobaotao; public class Office { private String officeNo =”001”; //省略 get/setter @Override public String toString() { return "officeNo:" + officeNo; } } |
Car 擁有兩個(gè)屬性:
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 類型的兩個(gè)屬性:
package com.baobaotao; public class Boss { private Car car; private Office office; // 省略 get/setter @Override public String toString() { return "car:" + car + "\n" + "office:" + office; } } |
我們?cè)?Spring 容器中將 Office 和 Car 聲明為 Bean,并注入到 Boss Bean 中:下面是使用傳統(tǒng) XML 完成這個(gè)工作的配置文件 beans.xml:
|
當(dāng)我們運(yùn)行以下代碼時(shí),控制臺(tái)將正確打出 boss 的信息:
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 容器已經(jīng)正確完成了 Bean 創(chuàng)建和裝配的工作。
使用 @Autowired 注釋
Spring 2.5 引入了 @Autowired 注釋,它可以對(duì)類成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作。來看一下使用@Autowired 進(jìn)行成員變量自動(dòng)注入的代碼:
package com.baobaotao; import org.springframework.beans.factory.annotation.Autowired; public class Boss { @Autowired private Car car; @Autowired private Office office; … } |
Spring 通過一個(gè) BeanPostProcessor 對(duì) @Autowired 進(jìn)行解析,所以要讓@Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。
|
這樣,當(dāng) Spring 容器啟動(dòng)時(shí),AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當(dāng)發(fā)現(xiàn) Bean 中擁有@Autowired 注釋時(shí)就找到和其匹配(默認(rèn)按類型匹配)的 Bean,并注入到對(duì)應(yīng)的地方中去。
按照上面的配置,Spring 將直接采用 Java 反射機(jī)制對(duì) Boss 中的 car 和 office 這兩個(gè)私有成員變量進(jìn)行自動(dòng)注入。所以對(duì)成員變量使用@Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。
當(dāng)然,您也可以通過 @Autowired 對(duì)方法或構(gòu)造函數(shù)進(jìn)行標(biāo)注,來看下面的代碼:
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; } … } |
這時(shí),@Autowired 將查找被標(biāo)注的方法的入?yún)㈩愋偷?Bean,并調(diào)用方法自動(dòng)注入這些 Bean。而下面的使用方法則對(duì)構(gòu)造函數(shù)進(jìn)行標(biāo)注:
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() 構(gòu)造函數(shù)有兩個(gè)入?yún)?,分別是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為Boss(Car car ,Office office) 的入?yún)韯?chuàng)建 Boss Bean。
當(dāng)候選 Bean 數(shù)目不為 1 時(shí)的應(yīng)對(duì)方法
在默認(rèn)情況下使用 @Autowired 注釋進(jìn)行自動(dòng)注入時(shí),Spring 容器中匹配的候選 Bean 數(shù)目必須有且僅有一個(gè)。當(dāng)找不到一個(gè)匹配的 Bean 時(shí),Spring 容器將拋出BeanCreationException 異常,并指出必須至少擁有一個(gè)匹配的 Bean。我們可以來做一個(gè)實(shí)驗(yàn):
<!-- --> |
由于 office Bean 被注釋掉了,所以 Spring 容器中將沒有類型為 Office 的 Bean 了,而 Boss 的office屬性標(biāo)注了 @Autowired,當(dāng)啟動(dòng) Spring 容器時(shí),異常就產(chǎn)生了。
當(dāng)不能確定 Spring 容器中一定擁有某個(gè)類的 Bean 時(shí),可以在需要自動(dòng)注入該類 Bean 的地方可以使用 @Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時(shí)也不報(bào)錯(cuò)。來看一下具體的例子:
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; } … } |
當(dāng)然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動(dòng)注入而又允許不注入的情況一般僅會(huì)在開發(fā)期或測(cè)試期碰到(如為了快速啟動(dòng) Spring 容器,僅引入一些模塊的 Spring 配置文件),所以@Autowired(required = false) 會(huì)很少用到。
和找不到一個(gè)類型匹配 Bean 相反的一個(gè)錯(cuò)誤是:如果 Spring 容器中擁有多個(gè)候選 Bean,Spring 容器在啟動(dòng)時(shí)也會(huì)拋出 BeanCreationException 異常。來看下面的例子:
… … |
我們?cè)?Spring 容器中配置了兩個(gè)類型為 Office 類型的 Bean,當(dāng)對(duì) Boss 的 office 成員變量進(jìn)行自動(dòng)注入時(shí),Spring 容器將無法確定到底要用哪一個(gè) Bean,因此異常發(fā)生了。
Spring 允許我們通過 @Qualifier 注釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:
@Autowired public void setOffice(@Qualifier("office")Office office) { this.office = office; } |
@Qualifier("office") 中的 office 是 Bean 的名稱,所以 @Autowired 和@Qualifier 結(jié)合使用時(shí),自動(dòng)注入的策略就從 byType 轉(zhuǎn)變成 byName 了。@Autowired 可以對(duì)成員變量、方法以及構(gòu)造函數(shù)進(jìn)行注釋,而@Qualifier 的標(biāo)注對(duì)象是成員變量、方法入?yún)ⅰ?gòu)造函數(shù)入?yún)?。正是由于注釋?duì)象的不同,所以 Spring 不將 @Autowired 和@Qualifier 統(tǒng)一成一個(gè)注釋類。下面是對(duì)成員變量和構(gòu)造函數(shù)入?yún)⑦M(jìn)行注釋的代碼:
對(duì)成員變量進(jìn)行注釋:
public class Boss { @Autowired private Car car; @Autowired @Qualifier("office") private Office office; … } |
對(duì)構(gòu)造函數(shù)入?yún)⑦M(jìn)行注釋:
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 結(jié)合使用,是對(duì) @Autowired 有益的補(bǔ)充。一般來講,@Qualifier 對(duì)方法簽名中入?yún)⑦M(jìn)行注釋會(huì)降低代碼的可讀性,而對(duì)成員變量注釋則相對(duì)好一些。
使用 JSR-250 的注釋
Spring 不但支持自己定義的 @Autowired 的注釋,還支持幾個(gè)由 JSR-250 規(guī)范定義的注釋,它們分別是 @Resource、@PostConstruct 以及 @PreDestroy。
@Resource
@Resource 的作用相當(dāng)于 @Autowired,只不過 @Autowired 按 byType 自動(dòng)注入,面@Resource 默認(rèn)按 byName 自動(dòng)注入罷了。@Resource 有兩個(gè)屬性是比較重要的,分別是 name 和 type,Spring 將@Resource注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動(dòng)注入策略,而使用 type 屬性時(shí)則使用 byType 自動(dòng)注入策略。如果既不指定 name 也不指定 type 屬性,這時(shí)將通過反射機(jī)制使用 byName 自動(dòng)注入策略。
Resource 注釋類位于 Spring 發(fā)布包的 lib/j2ee/common-annotations.jar 類包中,因此在使用之前必須將其加入到項(xiàng)目的類庫(kù)中。來看一個(gè)使用@Resource 的例子:
package com.baobaotao; import javax.annotation.Resource; public class Boss { // 自動(dòng)注入類型為 Car 的 Bean @Resource private Car car; // 自動(dòng)注入 bean 名稱為 office 的 Bean @Resource(name = "office") private Office office; } |
一般情況下,我們無需使用類似于 @Resource(type=Car.class) 的注釋方式,因?yàn)?Bean 的類型信息可以通過 Java 反射從代碼中獲取。
要讓 JSR-250 的注釋生效,除了在 Bean 類中標(biāo)注這些注釋外,還需要在 Spring 容器中注冊(cè)一個(gè)負(fù)責(zé)處理這些注釋的 BeanPostProcessor:
|
CommonAnnotationBeanPostProcessor 實(shí)現(xiàn)了 BeanPostProcessor 接口,它負(fù)責(zé)掃描使用了 JSR-250 注釋的 Bean,并對(duì)它們進(jìn)行相應(yīng)的操作。
@PostConstruct 和 @PreDestroy
Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執(zhí)行特定的操作,您既可以通過實(shí)現(xiàn) InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調(diào)用的操作方法。關(guān)于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業(yè)應(yīng)用開發(fā)精解》第 3 章進(jìn)行了詳細(xì)的描述,有興趣的讀者可以查閱。
JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個(gè)注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個(gè)注釋只能應(yīng)用于方法上。標(biāo)注了 @PostConstruct 注釋的方法將在類實(shí)例化后調(diào)用,而標(biāo)注了 @PreDestroy 的方法將在類銷毀之前調(diào)用。
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"); } … } |
您只需要在方法前標(biāo)注 @PostConstruct 或 @PreDestroy,這些方法就會(huì)在 Bean 初始化后或銷毀之前被 Spring 容器執(zhí)行了。
我們知道,不管是通過實(shí)現(xiàn) InitializingBean/DisposableBean 接口,還是通過 元素的init-method/destroy-method 屬性進(jìn)行配置,都只能為 Bean 指定一個(gè)初始化 / 銷毀的方法。但是使用@PostConstruct 和 @PreDestroy 注釋卻可以指定多個(gè)初始化 / 銷毀方法,那些被標(biāo)注 @PostConstruct 或 @PreDestroy 注釋的方法都會(huì)在初始化 / 銷毀時(shí)被執(zhí)行。
通過以下的測(cè)試代碼,您將可以看到 Bean 的初始化 / 銷毀方法是如何被執(zhí)行的:
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();// 關(guān)閉 Spring 容器,以觸發(fā) Bean 銷毀方法的執(zhí)行 } } |
這時(shí),您將看到標(biāo)注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動(dòng)時(shí),創(chuàng)建BossBean 的時(shí)候被觸發(fā)執(zhí)行,而標(biāo)注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關(guān)閉前銷毀Boss Bean 的時(shí)候被觸發(fā)執(zhí)行。
使用 簡(jiǎn)化配置
Spring 2.1 添加了一個(gè)新的 context 的 Schema 命名空間,該命名空間對(duì)注釋驅(qū)動(dòng)、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會(huì)做任何事情的,它僅提供元數(shù)據(jù)信息。要使元數(shù)據(jù)信息真正起作用,必須讓負(fù)責(zé)處理這些元數(shù)據(jù)的處理器工作起來。
而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數(shù)據(jù)的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊(cè)這些BeanPostProcessor 的方式,這就是 。請(qǐng)看下面的配置:
本文標(biāo)題:Spring注解詳解
本文URL:http://bm7419.com/article6/pscsig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、用戶體驗(yàn)、建站公司、企業(yè)建站、網(wǎng)頁(yè)設(shè)計(jì)公司、微信公眾號(hào)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
網(wǎng)頁(yè)設(shè)計(jì)公司知識(shí)