官术网_书友最值得收藏!

3.8 基于Annotation配置管理

Spring中,所有的Bean都必須通過配置文件進行管理。這樣處理的優勢在于可以利用配置文件實現程序控制,劣勢在于大型項目中可能出現配置文件過多的情況。為了彌補這一設計缺陷,Spring提供了Annotation配置支持。

提示:關于配置文件與Annotation。

Spring早期版本比較強調配置文件與程序相分離的設計原則。隨著Spring項目的不斷增多,開發人員面臨著大量配置文件的維護工作,所以后期的Spring版本提供了Annotation注解配置。利用這些注解配置和一些規則,可以避免配置文件過多,但配置文件并不會徹底消失。為了平衡配置文件的數量,Spring還提供了配置Bean類,即可通過Java類實現配置。這一點在本章后面的部分可以看見。

為了方便讀者理解Spring注解配置與實際開發的關聯關系,下面將通過一個簡單的業務層與數據層(不使用數據庫)調用模擬形式,來進行講解。調用關系如圖3-3所示。

圖3-3 實際調用還原

3.8.1 context掃描配置

要想使用Spring中的注解配置,需要先配置注解類的掃描包。也就是說,配置包下的所有注解都會自動生效,掃描包的配置則需要在項目中引入context命名空間,如圖3-4所示。

圖3-4 配置中引入context注解

引入context配置之后,還需要使用<context:component-scan>元素配置程序的掃描包,這樣配置包以及其子包下的所有程序類就都可以實現注解配置了。

范例:【mldnspring-base項目】修改spring-base.xml配置文件。

早期Spring版本中,要使用注解配置,需要先定義<context:annotation-config />元素,表示啟用注解。隨著版本提升,現在已經不需要進行配置了。在定義<context:component-scan>元素的掃描包時可以同時定義多個掃描包,使用“,”進行分隔。

提示:程序開發包。

本程序定義的掃描基礎包為cn.mldn.mldnspring,所以后續的DAO實現類必須定義在cn.mldn.mldnspring.dao.impl子包中,業務層實現類定義在cn.mldn.mldnspring.service.impl子包中,這樣就可以自動掃描這些類上的注解,從而實現自動配置。

3.8.2 資源掃描與注入

注解配置環境搭建完成后,如果想采用注解形式實現Bean配置,還需要在配置類上使用如下的4個注解(全部等價于<bean>功能)。

定義組件:org.springframework.stereotype.Component。

數據層注解:org.springframework.stereotype.Repository。

業務層注解:org.springframework.stereotype.Service。

控制層注解:org.springframework.stereotype.Controller。

提示:4個注解功能相同。

@Repository、@Service、@Controller 3個注解,如果開發者打開源代碼,會發現其中都包含了@Component注解(等價于配置文件中的<bean>元素定義,自動交由Spring管理)。實際上這4個注解的功能是完全相同的,Spring中為了描述的準確性,才設計了不同的名稱。

1.【mldnspring-base項目】定義IDeptDAO接口。

2.【mldnspring-base項目】定義IDeptDAO接口實現子類,該類將通過注解配置。

由于數據層需要進行持久化處理,所以本程序使用了@Repository注解進行Bean的定義。

提示:關于Bean的名稱。

上述程序雖然使用了@Repository注解,但卻等價于如下Spring配置項:

即注解配置時默認的Bean名稱為類名稱(首字母小寫)。

3.【mldnspring-base項目】定義IDeptService業務接口。

4.【mldnspring-base項目】定義IDeptService接口實現子類。

由于DeptDAOImpl子類上使用了@Repository注解,所以該類對象將由Spring自動管理。在業務層中使用@Resource注解實現了IDeptDAO子類對象的注入處理。DeptServiceImpl類上也提供有@Service注解,所以該類對象也將被Spring自動管理。

5.【mldnspring-base項目】編寫測試類,注入IDeptService接口實例。

測試程序會自動啟動Spring容器,加載spring-base.xml配置文件,并根據context掃描包配置自動獲取IDeptService接口實例,這樣測試類中就可以直接調用業務方法了。這種做法與Spring在實際開發之中的處理形式非常類似。

3.8.3 @Autowired注解

進行資源注入的時候,我們使用的是javax.annotation.Resource注解,但此注解并不是Spring的官方注解。Spring開發框架中還有一個org.springframework.beans.factory.annotation.Autowired注解,在不出現重名Bean的情況下,兩者的效果是完全一樣的。

范例:【mldnspring-base項目】修改之前的程序類,使用@Autowired注解替代@Resource注解。

此時的程序依然可以正常執行,即可以根據類型自動實現Bean對象的注入管理。但當Bean有兩個不同的實例化對象時,將無法準確地進行注入處理。

范例:【mldnspring-base項目】修改spring-base.xml配置文件,采用手動方式增加一個DeptServiceImpl子類配置。

      <bean id="deptServiceNew" class="cn.mldn.mldnspring.service.impl.DeptServiceImpl"/> 

這里,程序采用兩種配置方式,定義了兩個DeptServiceImpl子類對象。這種情況下,不管使用的是@Autowired還是@Resource類型注入,執行時都會出現如下錯誤提示信息:

該錯誤信息明確表示存在兩個同樣類型的IDeptService對象,Spring無法區分要注入的是哪個對象。對于該問題,有以下3種解決方案。

解決方案1:使用@Autowired注解,并采用優先選擇配置。

前面在講Bean配置的時候,曾經講過自動匹配處理,可以在配置文件中使用primary="true"進行優先選擇配置,此配置可以直接在類中使用@Primary注解完成。

此時將優先選擇注解配置的Bean類,這樣就不會出現Bean沖突問題。

解決方案2:使用@Resource注解,定義引入Bean名稱。

解決方案3:聯合使用@Autowired注解和@Qualifier注解。

@Resource雖然可以解決重名Bean的問題,但由于部分開發者認為其并不是Spring提供的注解,所以更愿意使用@Autowired。為了解決這個問題,在Spring開發框架中還可以使用@Qualifier注解來標注待注入的對象名稱。

如果程序直接使用@Autowired,將無法確定要導入的是哪個Bean對象。使用@Qualifier可以指明要導入的Bean名稱,從而避免混淆。

提示:@Resource注解與@Autowired注解的區別。

通過分析可以發現,實際上,@Resource=@Autowired+@Qualifier。默認情況下,@Resource與@Autowired會根據類型(byType)自動匹配注入對象。類型相同時,可通過名稱(byName)進行匹配,@Resource可直接通過name屬性設置Bean名稱,@Autowired必須結合@Qualifier注解來設置名稱。

3.8.4 使用Java類進行配置

項目中,如果覺得配置文件過多易導致配置混亂,可以使用Java程序類來實現Bean的配置處理。此模式基于context掃描包進行配置,同時需要用到@Configuration注解。

范例:【mldnspring-base項目】在掃描包中定義配置Bean。

本程序將配置類直接保存到了context掃描子包中,由于使用@Configuration注解,所以會自動將該類中有@Bean注解的配置項交由Spring容器管理。其中,@Bean(name="deptDAONew")注解的作用等同于在配置文件中編寫了如下配置項:

     <bean id="deptDAONew" class="cn.mldn.mldnspring.dao.impl.DeptDAOImpl" /> 

利用Bean實現的配置相對簡單,在Spring微架構開發中有著廣泛應用。

主站蜘蛛池模板: 沂水县| 邹平县| 济南市| 汤阴县| 西丰县| 英德市| 峨山| 高州市| 麟游县| 奇台县| 天长市| 庆云县| 英山县| 崇阳县| 额尔古纳市| 永登县| 大同县| 抚宁县| 镇雄县| 鹤山市| 鹤壁市| 庆安县| 健康| 武穴市| 新沂市| 大港区| 大名县| 莱州市| 曲沃县| 镇雄县| 巴彦淖尔市| 从江县| 伊川县| 横山县| 固安县| 佛冈县| 静宁县| 信丰县| 大悟县| 洪江市| 剑川县|