javascript
Spring入门 IOC
JAVA就業套餐課:https://edu.csdn.net/combo/detail/1230
課程說明
一、?技術概覽
輕量級的企業應用開發越來越受到廣大Java應用開發者的追捧,而Spring框架又是輕量級容器的杰出代表。由于Spring的使用日漸廣泛,因此已有許多應用服務器(WAS)的應用采用了Spring框架。本書先介紹Spring的依賴注入、面向切面編程、Spring抽象JDBC框架,然后介紹三大框架的整合。
Spring框架的核心思想我們可以用兩個字來描述,那就是“解耦”。應用程序的各個部分之間(包括代碼內部和代碼與平臺之間)盡量形成一種松耦合的結構,使得應用程序有更多的靈活性。應用內部的解耦主要通過一種稱為控制反轉(IOC)的技術來實現??刂品崔D的基本思想就是本來由應用程序本身來主動控制的調用等邏輯轉變成由外部配置文件來被動控制。由于控制反轉的概念相對比較廣泛,很多應用服務器實際上也實現了不同程度的控制反轉技術,只是這些應用服務器對應用程序的侵入性太強。因此Martin Fowler專門寫了一篇文章討論控制反轉這個概念,并提出一個描述更為準確的概念,叫依賴注入(Dependency Injection)。
Spring框架中的各個部分都充分使用了這種依賴注入的技術實現,從而給應用以最大的靈活度。實際上,這種依賴注入的參數化應用控制并不是Spring的首創,比如IBM的多渠道應用整合平臺(Branch Transformation Toolkit,BTT)很早就采用了這種外部參數化控制的技術。BTT中的“對象工廠”與Spring框架中的BeanFactory也有著異曲同工之妙。
Spring框架另外一個比較重要的技術是它對于面向切面的編程(AOP)的支持。隨著應用復雜度的逐漸上升和對應用靈活性要求的提高,IT邏輯和業務邏輯盡量分離的呼聲也越來越高。AOP技術作為實現這種分離的一種比較好的途徑而越來越受到大家的重視。Spring提供的是一種動態AOP實現,也即通過代理模式動態地在目標對象的方法前后插入相應的處理代碼。應用程序與底層應用服務器平臺的解耦也可以借助AOP技術來實現。Spring內置的AOP支持是一種錦上添花的功能。它使得一些本來必須由容器支持的功能,比如事務控制可以脫離開容器運行,從而達到“瘦身”的目的。這也是為什么Spring框架常被人成為輕量級容器的一個原因。
JDBC基于SQL,不要求我們掌握其他框架的查詢語言,簡單易學,因此學習成本低。另外,在使用 JDBC 時,可以更細致地調整數據訪問的性能。JDBC 還允許我們利用數據庫的特有功能,而其他框架可能不鼓勵甚至禁止使用它們。 但是JDBC并不完美,無論是執行查詢,更新,插入還是刪除操作, JDBC都要求我們正確地管理連接和語句,還要處理可能拋出的SQLException,及時的釋放資源。這顯然造成了大量的代碼重復。這似乎印證了 Pareto 法則:只有 20% 的代碼是查詢操作所必需的,而80%代碼是樣板代碼。Spring抽象JDBC框架基于模板設計模式,將上述必須都又和核心業務無關的樣板代碼封裝到模板方法中,以簡化開發,讓編程人員可以將精力集中在核心業務之上。
Spring框架可以與許多已有的框架技術結合使用。J2EE技術應用的一個重要特點是相關的開源社區非?;钴S。Web應用的不同層次都有非常多優秀的開源框架存在。比如Web層的Struts,ORM映射層的Hibernate等。Spring框架并不重新發明輪子,它的出現不是為了替代這些已有的框架。相反,Spring框架在設計上可以獨立構建應用或者結合已有的框架一起構建應用。另外一個值得指出的地方是Spring框架的幾大模塊之間相互耦合度很小,因此Spring框架的使用可以根據實際需要選其部分模塊循序漸進的使用,而非必須統統照搬。
?
本章簡介
Spring是用于簡化企業應用程序開發過程的開源框架,屬于輕量級的控制反向 (IOC,即 Inversion of control)和面向切面編程 (AOP,即 Aspect Oriented ?Programming)的容器框架。本章以 Spring的起源及背景為起點,介紹Spring的工作原理。然后以組裝計算機為貫穿案例介紹Spring Bean的封裝機制、Spring對Bean的管理,分別使用設值注入、構造注入、自動注入等方式組裝Bean。最后通過一個示例介紹集合屬性的使用。
?
1.1?Spring簡介
1.1.1?Spring 的歷史
Spring的基礎架構起源于2000年早期,創始人為畢業于悉尼大學的音樂學博士Rod Johnson。2002 年后期,Rod Johnson 發布了《Expert One-on-One J2EE 設計與開發》一書,在書中,他對傳統的J2EE技術(以EJB為核心)日益臃腫和低效提出了質疑,他覺得應該有更簡潔的做法,于是提出了Interface21,也就是Spring框架的雛形。他還隨書提供了Interface21 開發包以實現初步框架的開發,Interface21 即書中思想的具體實現。Rod Johnson 以 Interface21 開發包為基礎,通過改造與擴充將其升級為更加開放、清晰、全面、高效的開發框架——Spring。2003年2月,Spring 框架正式成為開源項目,并發布于SourceForge中。后期隨著數百甚至上千開發者貢獻各自的經驗,Spring 在改進與加強中變得日益強大,開發者的熱心與投入使 Spring 社區十分活躍。
?
Spring框架的發展與成熟,離不開日復一日為 Spring 社區默默地做出偉大貢獻的會員們。
1.1.1?Spring工作原理
Spring是一種通過JavaBean配置應用程序的方法。我們不需要通過new關鍵詞創建對象,而是在配置文件中配置JavaBean。當對象與對象之間有依賴關系的時候,我們也只需要在配置文件中把依賴關系體現出來,這些被配置的Bean將會納入Spring管理,放置于Spring容器中。我們只需要寫很少量的代碼便可得到Spring容器,并且從Spring容器中得到配置的JavaBean。這種解決依賴性的方法即控制反轉 (IOC,即Inversion of Control)或者依賴注入(Dependency Injection),從技術上來說,即使用某種容器組織相互依賴的對象。除了IOC之外,Spring還可以將分散在系統的公共代碼統一組織起來,在運行的時候加入到系統中,這就是AOP(面向切面編程)。
1.1.2?Spring框架簡介
Spring 是用于簡化企業應用程序開發過程的開源框架,屬于輕量級的控制反轉 (IOC)和面向切面編程 (AOP,即 Aspect Oriented Programming)的容器框架,解決了J2EE開發中許多常見的問題。我們需要了解一下Spring中的一些名詞:
(1)輕量級:以所占大小及系統開銷分析,Spring屬于輕量級。整個Spring框架可以打包為 1M左右的JAR包,且系統開銷較小。同時,Spring為非侵入式,若系統基于Spring開發,其所含的對象一般不依賴于Spring的類。
(2)IOC: IOC使對象被動接受依賴類,而并非主動獲取。也就是說,告訴 Spring“你”是什么,“你”需要什么對象,然后Spring會在系統運行到適當的時候,把“你”要的對象主動給“你”,同時也把“你”交給其他需要“你”的對象。所有的類的創建、銷毀都由Spring來控制,控制對象生存周期的不再是引用它的對象,而是 Spring。對于某個具體的對象而言,使用 Spring 之前是它控制其他對象,現在是所有對象都被 Spring 控制,所以叫控制反轉。在系統運行中,動態的向某個對象提供它所需要的其他對象,這一點是通過DI(依賴注入)實現的。
(3)AOP:面向切面編程(也叫面向方面編程),關注系統的橫向切面。通俗點說就是把代碼“切開”,然后在需要的位置上動態加入公共代碼。比如日志或者事務支持。
(4)容器:Spring 是一個包含且管理系統對象生命周期和配置的容器,在使用 Spring 應用開發的時候,幾乎所有的 JavaBean 對象都需要 Spring 來“盛放”。Spring 容器的作用是管理對象。
(5)Spring框架:Spring能夠通過簡單的組件組合為復雜的系統。Spring框架為分層架構,由7個定義良好的模塊組成,各模塊構建于核心容器之上,核心容器定義了創建、配置及管理Bean的方式,如圖 1.1.2 所示。
?
轉存失敗重新上傳取消
?
?
圖 1.1.2 中,各模塊 (或組件)可以單獨存在,也可以與其他一個或多個模塊聯合實現。各模塊的功能如下:
(1)Spring Core:核心容器,用于提供 Spring框架的基本功能,其主要組件為 BeanFactory,是工廠模式的實現。BeanFactory使用反向控制(IOC)模式將應用程序的配置及依賴性規范與實際應用程序代碼分開。
(2)Spring Context:核心模塊的BeanFactory使Spring成為容器,上下文 (Context)模塊使其成為框架。此模塊擴展了BeanFactory的概念,增加了對國際化(I18N,即Internationalization)消息、事件的傳播以及驗證的支持;同時,此模塊提供諸多企業服務,如電子郵件、JNDI訪問、EJB集成、遠程以及時序調度(Scheduling)服務,支持對模版框架 (如Velocity、FreeMarker)的集成。
(3)Spring AOP:通過配置管理特性,Spring AOP模塊將面向切面編程功能集成至框架中,使Spring框架管理的任何對象均支持AOP。Spring AOP模塊向基于 Spring的應用程序中的對象提供事務管理服務。此模塊無需依賴于EJB組件,可以使用 Spring AOP將聲明式事務管理集成至應用程序中。
(4)Spring DAO:JDBC DAO抽象層提供了意義重大的異常層次結構,簡化了錯誤處理過程并極大地減少了需要編寫的異常代碼 (如打開或關閉連接),運用此結構可以管理異常、處理不同數據庫供應商拋出的錯誤消息。Spring DAO的面向JDBC異常遵從通用的 DAO異常層次結構。
(5)Spring ORM:Spring框架中插入了若干ORM框架,提供ORM的對象關系工具,包括JDO、Hibernate以及iBatis SQL Map,都遵從Spring的通用事務及DAO異常層次結構。
(6)Spring Web:Web上下文模塊建立在應用程序上下文模塊之上,向基于Web 的應用程序提
供上下文,因而Spring框架支持與Struts集成。同時,Web模塊簡化了請求的處理過程以及將請求參數綁定至域對象的工作。
(7)Spring MVC:MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC框架變為高度可配置,它容納了大量視圖技術,包括JSP、Velocity、Tiles、iText及POI等。
創建Spring項目可以使用MyEclipse開發工具,先創建項目,然后增加Spring支持。操作過程如圖1.1.3和1.1.4所示。
?
轉存失敗重新上傳取消
?
轉存失敗重新上傳取消
?
圖1.1.4中類庫的添加只包含核心類庫,使用Spring控制反轉的時候一般不需要添加其他類庫。
1.1??Spring Bean封裝機制
1.1.1?Spring Bean?
Spring以Bean的方式管理所有的組件,J2EE 的全部組件都使用Bean管理。在Spring中,
除了標準的JavaBean,其他任何對象和組件都可以作為Bean。
應用中各層的對象均由Spring管理,對象以Bean方式存在。Spring負責創建Bean的實例并管理其生命周期,Bean運行于Spring的容器。Spring上下文是生產Bean的工廠,Bean是Spring工廠生產的實例。Spring產生工廠時,需要確定每個Bean的實現類;Bean實例的使用者面向接口,因此無須關心Bean實例的實現類。Spring工廠負責維護Bean實例的實例化,使用者則無須關心。
Bean的定義通常使用XML配置文件,正確定義的Bean 由Spring提供實例化以及依賴關系的注入等。最簡單的Spring配置文件代碼如示例1.1所示。
示例1.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:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> </beans>?
Spring的schemaLocation詳細規定了Spring配置文件的合法元素、各元素出現的先后順序、各元素的合法子元素以及合法屬性等。
增加對實體對象管理的Bean,配置文件代碼如示例1.2所示。
?
示例1.2
?
<?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:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"><bean id="user" class="com.hr.entity.UserVo" abstract="false" lazy-init="default" autowire="default" /> </beans>?
上述代碼中定義了UserVo對象。XML中Bean節點的部分屬性如下:
?
<bean id="beanId" name ="beanName" class="beanClass" parent="parentBean" abstract="true | false" scope="prototype|singleton" lazy-init="true | false | default" autowire="no | byName | by Type | constructor | auto detect |default"> </ bean>?
?
?
以上屬性的含義如表 1-1-l所示。
表1-1-1 Bean屬性
| 屬性 | 含義 |
| id | Bean的唯一標識名,必須為合法的XML ID,在整個XML文檔中唯一,如果沒有特殊需要,我們在標識一個Bean的時候,一般推薦使用id。 |
| name | 用于為id創建一個或多個別名,可以是任意字母或者符號,多個別名之間以逗號或空格分隔。 |
| class | 用于定義類的全限定名(包名加類名),Spring在創建對象的時候需要用到此屬性,因此該屬性不能指定接口。 |
| parent | 子類Bean定義其所引用的父類Bean,繼承父類的所有屬性。值得一提的是,在寫代碼的時候,即便是兩個類之間沒有繼承關系,我們同樣可以使用該屬性。 |
| abstract | 用于定義Bean是否為抽象Bean,默認為false,表示此Bean將不會被實例化。一般用于父類Bean,可以在子類繼承的時候使用。 |
| scope | 用于定義Bean的作用域,singleton表示在每個Spring IoC容器中一個bean定義對應一個對象實例,即Spring使用單例模式獲取實例。prototype表示一個bean定義對應多個對象實例,即非單例模式 |
| lazy-init | 用于定義Bean是否實現初始化,默認為default。若為true,將在BeanFactory啟動時初始化所有Singleton Bean;若為false,則在Bean請求時創建Singleton Bean |
| autowire | 用于定義Bean的自動裝配方式,默認為default,包括不使用自動裝配功能、通過Bean的屬性名實現自動裝配、通過Bean的類型實現自動裝配、通過Bean類的反省 (Introspection)機制決定選擇使用constructor或者byType。 |
1.1.1?Application Context
Spring包括兩種不同的容器:BeanFactory 和 ApplicationContext。BeanFactory提供基本的IOC支持;ApplicationContext則基于BeanFactory,提供應用程序框架服務。Spring提供了BeanFactory與 ApplicationContext 的多個實現。
ApplicationContext包括 BeanFactory 的全部功能,除非應用程序對性能要求很高時才考慮BeanFactory,其他情況下建議優先使用ApplicationContext。
應用中出現多個配置文件時,應采用BeanFactory的子接口ApplicationContext創建 BeanFactory的實例。ApplicationContext通常使用ClassPathXmlApplicationContext實現類,該類以classpath路徑下的XML配置文件創建ApplicationContext。使用該類創建Spring容器的代碼如示例1.3所示。
示例1.3
// 搜索classpath路徑,以classpath路徑下的applicationContext.xml創建對象ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
在實際應用中,會將Spring配置分別放在不同的配置文件中,如果一個應用中有兩個配置文件application.xml和bean.xml,則創建容器實例的方法如示例1.4所示。
示例1.4
// 搜索classpath路徑,以classpath路徑下的
//applicationContext.xml和bean.xml創建ApplicationContext。?
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","bean.xml"});
ApplicationContext接口包括以下 3 個重要方法:
(1)containsBean(String name)方法。
//判斷Spring容器是否包含ID為?user的Bean
boolean flag=applicationContext.containsBean("user");
(2)getBean(String name)方法。
//返回ID為?user的Bean
UserVo userBean= (UserVo)applicationContext.getBean("user");
該方法的功能是從Spring容器中獲取一個對象,該方法的參數可以是Spring配置文件中Bean的id或者name,如果name指定了多個標識,只需傳入一個標識。
(3)getType(String name)方法。
//返回:ID為?user 的類型
Class beanType= applicationContext.getType("user");
以下示例將從Spring容器中獲取一個user對象,并輸出user的信息。
示例1.5
// 以classpath路徑下的applicationContext.xml創建Spring容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "applicationContext.xml"); // 從Spring容器中獲取ID為user的Bean UserVo user = (UserVo) applicationContext.getBean("user"); // 封裝姓名和年齡 user.setName("張三豐"); user.setAge(100); // 輸出該Bean的信息 user.printInfo();從示例1.5我們發現Bean的創建將交給Spring管理,我們要做的就是在Spring配置文件中對Bean配置即可。
1.1?Spring DI/IOC
1.1.1?什么是Spring的依賴注入
我們先看看什么叫依賴。在生活中,依靠別人或者別的事物而不能獨立或者自立,我們稱為依賴。那么在應用中,什么叫依賴呢?
依賴指的是兩個實例之間的關系。其中一個實例是獨立的,另一個實例是非獨立的(依賴的),它依靠另外一個實例。比如計算機對象,它包含主機對象和顯示器對象。如果沒有主機對象或者顯示器對象,則計算機對象就是不完整的,不能正常使用,我們就說計算機對象依賴于主機對象和顯示器對象。
那么什么是注入呢?
計算機對象離不開主機對象和顯示器對象,程序在運行過程中,我們必須給計算機對象提供它所需要的主機對象和顯示器對象,把主機對象和顯示器對象像“打針”一樣提供給計算機對象,這個過程就叫做注入。
也就是說,如果一個對象需要另外一個對象才能正常使用,我們在程序運行的時候,給該對象提供它所需要的對象,這就是“依賴注入”。我們知道,Spring將會管理幾乎所有的Bean對象,而對象與對象之間可能存在依賴關系,在程序運行過程中,Spring把我們所需要的對象都拼裝好,這就是Spring的依賴注入。
在傳統的 Java設計中,當 Java實例的調用者創建被調用的 Java實例時,要求被調用的 Java類出現在調用者的代碼中,二者之間無法實現松耦合。工廠模式則對此進行了改進,使調用者無須關心被調用者的具體實現過程,只要獲得符合某種標準 (接口)的實例即可使用。其調用的代碼面向接口編程,支持調用者與被調用者解耦,因此工廠模式得以大范圍地使用。但在工廠模式中,調用者需要自行定位工廠,與特定工廠耦合,所以僅在一定程度上實現了調用者與被調用者的解耦。Spring 的出現使調用者無須自行定位工廠,當程序運行至需要被調用者時,系統將自動提供被調用者實例。事實上,調用者與被調用者均由 Spring管理,二者之間的依賴關系由Spring提供。
下面以計算機的組裝為例來演示此過程。計算機由主機和顯示器組成,我們需要輸出一臺計算機的信息,比如該計算機由什么型號的主機、什么型號的顯示器組成。下面我們一起來分析并設計該系統。
主機設計成一個類,該類(MainFrame)中有一個方法,用來輸出主機的型號,如示例1.6所示。
示例1.6
?
private String modelType;//型號 // 輸出主機信息 public void printMainFrameInfo() {System.out.println("主機型號:" + modelType); } //setter & getter顯示器設計成一個接口,該接口(Display)聲明一個輸出顯示器信息的方法,如示例1.7所示。
示例1.7
public void printDisplayInfo();
顯示器接口有兩個實現,分別是三星顯示器和LG顯示器,如示例1.8所示。
示例1.8
?
//三星顯示器 public class SamSungDisplay implements Display {public void printDisplayInfo() {System.out.println("顯示器:三星顯示器");} } //LG顯示器 public class LgDisplay implements Display {public void printDisplayInfo() {System.out.println("顯示器:LG顯示器 ");} }?
計算機由主機和顯示器組成,因此計算機類(Computer)有兩個屬性,一個是主機,一個是顯示器,如示例1.9所示。
示例1.9
?
private MainFrame mainFrame;// 主機 private Display display;// 顯示器接口// 輸出計算機配置信息public void printComputerInfo() {System.out.println("計算機配置如下:");mainFrame.printMainFrameInfo();// 輸出主機信息display.printDisplayInfo();// 輸出顯示器信息} //setter & getter?
根據需求,計算機依賴于主機和顯示器,因此可以使用Spring的依賴注入來實現。我們需要在配置文件中配置三星顯示器、LG顯示器和計算機。
三星顯示器的配置如示例1.10所示。
示例1.10
<bean id="samsung" class="s3spring.ch01.computer.mainframe.SamSungDisplay" />
LG顯示器的配置如示例1.11所示。
示例1.11
<bean id="lg" class="s3spring.ch01.computer.mainframe.LgDisplay" />
主機的modelType屬性是直接量,直接量指的是基本數據類型和字符串,對直接量的注入,我們可以使用<value/>元素來指定。主機的配置如示例1.12所示。
示例1.12
<bean id="mainFrame" class="s3spring.ch01.computer.mainframe.MainFrame">
<property name="modelType" value="三星高配主機"/>
</bean>
目前為止,我們已經把主機對象和顯示器對象交給了Spring,接下來,我們需要讓Spring管理計算機對象,計算機對象對主機對象和顯示器對象有依賴,我們需要用Spring的依賴注入來實現。
Spring的依賴注入對調用者與被調用者幾乎無任何要求。依賴注入通常分為設值注入、構造注入、自動注入等。
1.1.1?設值注入方式
設值注入是指通過setter方法傳入被調用者的實例,所以Bean的屬性要求有對應的setter和getter方法,此方式因簡單直觀而得以廣泛使用。
計算機的屬性為主機和顯示器,我們可以使用<ref/>元素來指定,該元素用來將bean中指定屬性的值設置為對容器中的另外一個bean的引用,采用設值注入方法的配置如示例1.13所示。
示例1.13
?
<!-- 計算機的配置 --> <bean id="computer" class="s3spring.ch01.computer.Computer"><!-- 設值注入主機,name對應computer的屬性,ref對應所依賴的bean--><property name="mainFrame" ref="mainFrame"/><!-- 設值注入三星顯示器 --><property name="display" ref="samsung"/> </bean>?
如果mainFrame、samsung和computer這三個Bean的配置在同一個配置文件,我們也可以把<property name=“mainframe”?ref=“mainframe”/>更改為
<property name=“mainframe”?><ref local=“mainframe”/></property>。如果mainFrame、samsung和computer不在同一個配置文件中,則需要更改為<property name=“mainframe”><ref bean=“mainframe”/></property>,無論是local還是bean都可以指定為一個所依賴的Bean的id或者name。
由配置文件可知,Spring在管理Bean時非常靈活。Bean與 Bean 間的依賴關系在配置文件中組織,并非在代碼中編寫。Spring通過配置文件精確地為每個Bean注入實例化的屬性。因此,配置文件Bean的class元素不能為接口,只能為實現類。
Spring 自動管理Bean定義property元素,在執行無參的構造方法和創建默認的Bean 的實例后,Spring會調用對應的setter方法注入屬性值。property定義的屬性值不再由 Bean創建或管理,而是被動接受Spring的注入。Bean的 ID 屬性為其唯一標識,程序通過 ID 屬性對Bean進行訪問,Bean與 Bean間的依賴關系也由 ID屬性實現。設值注入的測試代碼如示例1.14所示。
示例1.14
?
ApplicationContext applicationContextContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Computer computer=(Computer)applicationContextContext.getBean("computer");//輸出計算機的配置信息 computer.printComputerInfo();?
目前為止,我們成功的從Spring容器中獲取了計算機對象。Spring的依賴注入使得我們在維護項目的時候變的非常簡單,如果把顯示器更改LG顯示器,我們并不需要修改任何代碼,修改配置文件即可實現,配置文件的修改如下。
<property name="display" ref="lg"/>
1.1.1?構造注入方式
構造注入是指通過構造方法完成依賴關系的注入,并非 setter方法。將以上設值注入按構造注入重新實現,則需要在Computer中增加帶參構造方法,如示例1.15所示。
示例1.15
?
public Computer(MainFrame mainFrame, Display display) {this.mainFrame = mainFrame;this.display = display; }?
Spring配置文件需要修改,修改后如示例1.16所示。
示例1.16
?
<bean id="computer" class="s3spring.ch01.computer.Computer"> //構造注入主機和顯示器<constructor-arg index="0" ref="mainFrame" /><constructor-arg index="1" ref="samsung" /> </bean>?
采用構造注入方式時,Spring容器將會在程序運行時調用Computer的帶參構造方法來創建實例,該帶參構造有兩個參數,index指的是第幾個參數,ref指傳入該參數的Bean。其執行效果與設值注入完全相同,區別在于屬性的創建時機不同。設值注入創建默認的Bean實例后,調用對應的 setter方法注入依賴關系。構造注入則在創建 Bean實例時完成依賴關系的注入。
1.1.1?自動注入
Spring容器可以自動注入(autowire)相互協作bean之間的關聯關系。因此,如果可能的話,可以自動讓Spring通過檢查BeanFactory中的內容,來替我們指定bean的協作者(其他被依賴的bean)。由于autowire可以針對單個bean進行設置,因此可以讓有些bean使用autowire,有些bean不采用。autowire的方便之處在減少或者消除屬性或構造器參數的設置,這樣可以簡化配置文件,如果直接使用property和constructor-arg注入依賴的話,那么將總是覆蓋自動裝配,在xml配置文件中,可以在<bean/>元素中使用autowire屬性指定,如表1-1-2所示。
表1-1-2 autowire屬性
| 模式 | ?說明 |
| no | 不使用自動裝配。必須通過ref元素指定依賴,這是默認設置。由于顯式指定協作者可以使配置更靈活、更清晰,因此對于較大的部署配置,推薦采用該設置。 |
| byName | 根據屬性名自動裝配。此選項將檢查容器并根據名字查找與屬性完全一致的bean,并將其與屬性自動裝配。 |
| byType | 如果容器中存在一個與指定屬性類型相同的bean,那么將與該屬性自動裝配。如果存在多個該類型的bean,那么將會拋出異常,并指出不能使用byType方式進行自動裝配。若沒有找到相匹配的bean,則屬性不會被設置。 |
如果把配置文件修改為示例1.17所示,則采用自動裝配來組裝計算機。
示例1.17
?
<bean id="computer" class="s3spring.ch01.computer.Computer" autowire="byName"><property name="display" ref="samsung"></property> </bean>?
由于使用byName自動裝配,容器會檢查ID和Computer的兩個屬性mainFrame以及display名稱匹配的Bean并注入,由于存在ID為mainFrame的Bean,所以Computer的mainFrame屬性被自動注入,而display是顯式注入,所以覆蓋了display屬性的自動注入。
1.1.1?集合屬性
通過<list/>、<set/>、<map/>及<props/>元素可以定義和設置與Java Collection類型對應List、Set、Map及Properties的值。示例1.18中定義TestBean類,該類有四個屬性,分別是List、Map、Properties、Set類型。
?
private List list; private Map map; private Properties prop; private Set set;?
對TestBean類的配置如示例1.19所示。
示例1.19
<bean id="testBean" class="com.bean.TestBean"> <!--list屬性的配置 --><property name="list"><list><value>v1</value><value>v2</value></list></property><!-- map屬性的配置 --> <property name="map"><map><entry key="k1"><value>v1</value></entry><entry key="k2"><value>v2</value></entry></map></property> <!-- prop屬性的配置 --><property name="prop"><props><prop key="k1">str1</prop><prop key="k2">str2</prop></props></property><!-- set屬性的配置 --><property name="set"><set><value>v1</value><value>v2</value></set></property> </bean>程序運行的時候,我們從Spring容器中獲取testBean實例,該實例的四個集合屬性中將會包含指定的對象。
1.1.1?Spring 注入方式的比較
1. 設值注入的特點
對于習慣了傳統JavaBean開發的程序員而言,通過setter方法設定依賴關系更加直觀自然。當依賴關系(或繼承關系)較復雜時,構造注入方式的構造函數相當龐大,且需要在構造函數中設定所有依賴關系,此時使用設值注入方式則簡單快捷。除此之外,某些第三方類庫要求組件必須提供默認的構造函數 (如 Struts 中的 Action),此時構造注入方式的依賴注入機制會突顯局限性,難以完成預期的功能,必須通過設值注入實現。
2. 構造注入的優點
在構造期即創建完整、合法的對象,構造注入無疑是此Java設計原則的最佳響應者。
而且構造注入還避免了編寫繁瑣的setter方法,所有的依賴關系都在構造函數中設定,使依賴關系集中呈現,可讀性增加。由于不存在 setter方法,而是在構造時由容器一次性設定依賴關系。因此,組件在創建之后即處于相對穩定狀態,無須擔心上層代碼在調用過程中執行setter方法時破壞組件之間的依賴關系。對于 Singleton模式組件,這種破壞將對整個系統產生重大的影響。通過構造注入,可以在構造函數中決定依賴關系的注入順序。對于大量依賴外部服務的組件而言,依賴關系的獲取順序至關重要。
1.1?基于注解的容器配置
基于注解(Annotation)的配置有越來越流行的趨勢,Spring順應這種趨勢,從2.5版起提供了完全基于注解配置 Bean、裝配 Bean 的功能,您可以使用基于注解的 Spring IoC 替換原來基于 XML 的配置。
我們仍然使用計算機組裝的例子來講解基于注解的IOC容器配置語法。
1.1.1?使用?@Component注解配置bean
只需要在類的定義語句上方加上一個 @Component 注解,就將該類定義為一個bean了,請看示例1.20,將Computer、MainFrame、SamSungDisplay、LgDisplay配置成bean:
示例1.20?
?
@Component public class Computer { private MainFrame mainFrame;// 主機private Display display;// 顯示器接口// 輸出計算機配置信息public void printComputerInfo() {System.out.println("計算機配置如下:");mainFrame.printMainFrameInfo();// 輸出主機信息display.printDisplayInfo();// 輸出顯示器信息} }@Component public class MainFrame {private String modelType;// 型號// 輸出主機信息public void printMainFrameInfo() {System.out.println("主機型號:" + modelType);} } @Component public class SamSungDisplay implements Display {public void printDisplayInfo() {System.out.println("顯示器:三星顯示器");} } @Component public class LgDisplay implements Display {public void printDisplayInfo() {System.out.println("顯示器:LG顯示器 ");} }?
如上代碼所示,我們通過@Component注解分別將Computer、MainFrame、SamSungDisplay、LgDisplay配置成了bean(注意,在后面的示例中,我們會默認已經配置了上述4個bean)。bean名稱默認為將第一個字母轉換為小寫的類名。如Computer類的bean默認名稱是computer。上述代碼的等價xml配置是:
<bean id="samSungDisplay" class="s3spring.ch01.computer.annotation.SamSungDisplay" /> <bean id="lgDisplay" class="s3spring.ch01.computer.annotation.LgDisplay" /> <bean id="mainFrame" class="s3spring.ch01.annotation.computer.MainFrame"/> <bean id="computer" class="s3spring.ch01.annotation.computer.Computer"/>@Component注解唯一的一個可選參數是value,用于指定bean的名稱(即id值,所以必須是唯一的),如示例1.21所示,聲明Computer類為一個bean,id為computer:
示例1.21
?
@Component(value=”computer”)
public class Computer { …… }
可以省略參數名稱,簡寫為:
@Component(”computer”)
public class Computer { …… }
?
Spring還提供了更加細化的用于定義bean的注解形式:@Repository、@Service、@Controller,它們分別對應數據訪問層bean,業務層bean,和視圖層bean。目前版本中,這些注解與@Component的語義是一樣的,完全通用,在Spring以后的版本中可能會給它們追加更多的語義。所以,我們推薦使用@Repository、@Service、@Controller來替代@Component。
1.1.1?掃描?@Component標注的類
在使用?@Component?注解后,Spring 容器必須啟用類掃描機制,以找到所有使用@Component標注的類,將它們作為bean來管理。從Spring 2.5開始, 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置,引入context命名空間,并掃描bean:
示例1.22?
?
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="s3spring.ch1.annotation.computer"/></beans>?
?
Spring 容器在初始化時會掃描 <context:component-scan/> 標簽的 base-package 屬性指定的類包及其遞歸子包中所有的類,找出 @Component標注的類,將它們配置成bean。然后,我們就可以通過Spring 容器的工廠方法獲取并使用bean了。請看示例1.23,通過Spring容器獲取Computer bean:
示例1.23?
?
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Computer c = ac.getBean(Computer.class);?
執行示例1.23,如果沒有拋出任何異常,即表示能夠正常獲得bean。
1.1.1?使用?@Scope注解配置bean 的作用域
@Scope用于定義bean的作用域,singleton表示在每個Spring IoC容器中一個bean定義對應一個對象實例,即Spring使用單例模式獲取實例。prototype表示一個bean定義對應多個對象實例,即非單例模式,我們常稱作多例。默認情況下,Spring bean 的作用域為 singleton。示例1.24 將Computer類配置成一個“多例”的bean:
示例1.24
@Component
@Scope(value="prototype")
public class Computer { …… }
可以省略參數名稱,簡寫為:
@Component
@Scope("prototype")
public class Computer { …… }
1.1.2?使用?@Autowired注解
從Spring 2.5版本起, Spring引入了?@Autowired?注解,它可以對類成員變量、方法及構造函數進行標注,以完成自動裝配依賴的工作。
來看一下示例1.25,使用?@Autowired?為成員變量自動注入依賴:
示例1.25?
?
@Component @Scope("prototype") public class Computer {@Autowiredprivate MainFrame mainFrame;// 主機 @Autowiredprivate Display display;// 顯示器接口// 輸出計算機配置信息public void printComputerInfo() {System.out.println("計算機配置如下:");mainFrame.printMainFrameInfo();// 輸出主機信息display.printDisplayInfo();// 輸出顯示器信息} }?
?
?
將?@Autowired?標注于實例屬性mainFrame和display上面,Spring將直接采用?Java 反射機制獲取?mainFrame?和?display?屬性的類型,再根據類型查找“唯一”匹配的bean來進行依賴自動注入.(如果bean的類型與屬性的類型相同,或者bean的類型是屬性類型的子類型或接口實現,則類型匹配)。一般推薦將?@Autowired放在setter方法之上。
由于和mainFrame屬性類型匹配的bean只有MainFrame 一個,所以自動裝配依賴可以順利進行。但是和display?屬性的類型匹配的bean有兩個(SamSungDisplay和LgDisplay都實現了Display接口,而display屬性類型正是?Display),此時Spring 應用容器不知道該用哪一個bean為Computer的display屬性注入依賴值,從而導致創建Computer bean失敗,拋出BeanCreationException。異常信息如下:
Error creating bean with name 'computer': Injection of autowired dependencies failed;
……
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [s3spring.ch1.annotation.computer.Display] is defined: expected single matching bean but found 2: [lgDisplay, samSungDisplay]
那么如何解決根據類型返回多個bean導致的創建bean失敗的問題呢?答案是指定需要注入的bean 的名稱。要為Computer bean的display屬性注入三星顯示器,就需要告訴Spring我們需要的是符合Display類型,且id為“samSungDisplay”的bean。
指定依賴bean名稱的方法有兩種:
l?把屬性名稱做為依賴bean名稱
l?使用?@Qualifier 注解明確指定依賴bean的名稱,我們將在1.4.5小節講解
將display屬性改名為“samSungDisplay”,當Spring 應用容器根據屬性類型返回多個bean時,會繼續以反射的方式獲得屬性的名稱?“samSungDisplay”,從而找到同名的bean。請看示例1.26:
示例1.26
?
@Component @Scope("prototype") public class Computer {@Autowiredprivate MainFrame mainFrame;// 主機 @Autowiredprivate Display samSungDisplay;// 顯示器接口// 輸出計算機配置信息public void printComputerInfo() {System.out.println("計算機配置如下:");mainFrame.printMainFrameInfo();// 輸出主機信息samSungDisplay.printDisplayInfo();// 輸出顯示器信息} }?
我們也可以使用setter方法,構造方法和其它的方法,根據參數類型和名稱來注入依賴bean,請看示例1.27:
示例1.27
@Component @Scope("prototype") public class Computer {private MainFrame mainFrame;// 主機private Display display;// 顯示器接口 @Autowired //構造函數的變量名與容器中的對象名保持一致,否則需要@Qualifier指定注入 Bean 的名稱public Computer(MainFrame mainFrame, Display samSungDisplay) {super();this.mainFrame = mainFrame;this.display = samSungDisplay;}…… }?
1.1.1?使用?@Qualifier注解為自動注入指定依賴bean的名稱
?
Spring 允許我們通過?@Qualifier?注解指定注入 Bean 的名稱。
示例1.28
?
@Component @Scope("prototype") public class Computer {@Autowiredprivate MainFrame mainFrame;// 主機 @Autowired @Qualifier("samSungDisplay")private Display display;// 顯示器接口…… }?
使用@Qualifier注解為方法指定要注入的依賴bean的名稱。
示例1.29?
?
@Component @Scope("prototype") public class Computer {private MainFrame mainFrame;// 主機private Display display;// 顯示器接口 @Autowired public Computer( MainFrame mainFrame, @Qualifier("samSungDisplay") Display display ) {super();this.mainFrame = mainFrame;this.display = display;}…… }?
總結,使用 @Autowired ?注解自動裝配依賴的過程如下:
1)?首先根據屬性的類型(或方法、構造方法參數的類型)在Spring 應用容器中查找類型匹配的bean
2)?如果沒有類型匹配的bean,拋出BeanCreationException;如果只有一個,則注入依賴,完成自動裝配;如果不只一個,則繼續執行步驟3;
3)?如果通過?@Qualifier指定了bean 名稱,則從所有符合類型的bean中返回指定的bean,完成自動裝配;如果沒有通過?@Qualifier制定bean 名稱,則通過反射技術獲取當前屬性的名稱作為bean 名稱返回指定的bean,完成自動裝配;
1.1.1?使用?@Resource 注解注入依賴
Spring 不但支持自己定義的@Component、@Scope、?@Autowired、?@Qualifier注解,還支持幾個由?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執行結果,即使name不一致也可以注入,就是按照類型了。
請看示例1.30:
示例1.30
?
@Component @Scope("prototype") public class Computer { @Resourceprivate MainFrame mainFrame;//采用屬性名稱作為依賴bean的名稱@Resource(name=”samSungDisplay”)private Display display;// 采用@Resource注解name參數值作為依賴bean的名稱…… }1.1.1?@PostConstruct 和?@PreDestroy
?
Spring 容器中的?Bean 是有生命周期的,Spring 允許在?Bean 在初始化完成后以及?Bean 銷毀前執行特定的操作。JSR-250 為初始化之后/銷毀之前指定執行方法定義了兩個注解類,分別是 @PostConstruct 和 @PreDestroy,這兩個注解只能應用于方法上。標注了 @PostConstruct 注解的方法將在類實例化后調用,而標注了 @PreDestroy 的方法將在類銷毀之前調用。請看示例1.31:
示例1.31
?
@Component @Scope("prototype") public class Computer {…… @PostConstruct public void postConstruct1(){System.out.println("執行postConstruct1");}@PreDestroy public void preDestroy1(){System.out.println("執行preDestroy1"); }}?
執行示例1.31,在bean被初始化時,會輸出“執行postConstruct1”。在bean被銷毀時,會輸出“執行preDestroy1”。我們通??梢栽跇俗⒘?@PostConstruct的方法中完成一些資源初始化的工作,在?標注了 @PreDestroy 的方法中完成一些釋放資源的操作。注意的是@PreDestroy要在容器關閉之前,所以要使用以下代碼初始化容器:
?
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext”); //釋放容器資源,會調用@PreDestroy注解的方法 context.close();[新添加] 或者 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext”); context.destory();?
?
?
執行示例1.31,在bean被初始化時,會輸出“執行postConstruct1”。在bean被銷毀時,會輸出“執行preDestroy1”。我們通??梢栽跇俗⒘?@PostConstruct的方法中完成一些資源初始化的工作,在?標注了 @PreDestroy 的方法中完成一些釋放資源的操作。注意的是@PreDestroy要在容器關閉之前,所以要使用以下代碼初始化容器:
?
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext(“applicationContext”);
//釋放容器資源,會調用@PreDestroy注解的方法
context.close();
或者
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext(“applicationContext”);
context.destory();
注意:如果Bean類配置了@Scope("prototype")則不會調用@PreDestory注解的方法.
本章總結
?
?Spring框架
?Spring 是用于簡化企業應用程序開發過程的開源框架
?Spring 的核心是一個控制反轉容器
?Spring 提供了AOP實現
?Spring 提供了常用WEB框架整合的支持
?Spring 提供了對ORM技術整合的支持
?Spring Bean 封裝機制
?Spring以Bean的方式管理所有的組件
?Spring包括兩種不同的容器:BeanFactory 和 ApplicationContext
?依賴注入
?設置注入
?構造器注入
?自動注入
?集合注入
?基于注解配置應用容器
?@Component
?@scope
?@Autowired
?@Qualifier
? @Resource
?@PostConstruct?和?@PreDestroy。
任務實訓部分
?
1: 使用Spring獲取Bean對象
訓練技能點
?Spring Bean的管理
?Bean的配置
?Spring容器的創建
需求說明
我們在配置電腦的時候,不同型號對應不同的硬盤,先要求編寫Spring程序,能夠根據不同的硬盤型號,得到不同的硬盤實例。
實現思路
(1)?定義硬盤接口。
(2)?定義不同型號的硬盤實現類。
(3)?在Spring配置文件中配置硬盤實現類。
(4)?創建ClassPathXmlApplicationContext并獲取硬盤對象。
關鍵代碼
(1)?定義硬盤接口。
public interface HardDisk {
public void printHardDiskInfo();//輸出硬盤信息
}
(2)?定義兩個硬盤實現類。
//希捷硬盤
public class SeaGateHardDisk implements HardDisk {
public void printHardDiskInfo() {
System.out.println("希捷160G硬盤");
}
}
//三星硬盤
public class SamSungHardDisk implements HardDisk {
public void printHardDiskInfo() {
System.out.println("三星250G硬盤");
}
}
(3)?使用<bean>標簽對三星硬盤、希捷硬盤進行配置,三星硬盤的標識為samSungHardDisk,希捷硬盤的標識為seaGateHardDisk,配置文件中的的關鍵代碼如下所示。
//三星硬盤的配置
<bean id="samSungHardDisk" class="bean.SamSungHardDisk"/>
//希捷硬盤的配置
<bean id="seaGateHardDisk" class="bean.SeaGateHardDisk"/>
(4)?編寫測試類測試。
ApplicationContext context =
???????new ClassPathXmlApplicationContext("applicationContext.xml");
// 獲取三星硬盤
HardDisk hardDisk = (HardDisk) context.getBean("samSungHardDisk");
hardDisk.printHardDiskInfo();
// 獲取希捷硬盤
hardDisk = (HardDisk) context.getBean("seaGateHardDisk");
hardDisk.printHardDiskInfo();
2:?設值注入實現打印機組裝
訓練技能點
?Spring設值注入
需求說明
打印機由墨盒和紙張組成,墨盒分彩色墨盒和黑白墨盒,紙張有A3紙和A4紙。我們在打印的時候,經常切換墨盒和紙張,現要求編寫一個Spring程序組裝一臺打印機并輸出組成該打印機的紙張和墨盒信息。
實現思路
(1)?定義墨盒接口(Ink)和紙張接口(Paper),Ink接口中聲明方法 printInkInfo()輸出墨盒信息,Paper接口中聲明方法printPaperInfo()輸出紙張信息。
(2)?定義打印機類(Printer)。打印機類中包含方法printerInfo(),輸出打印機的配置。
(3)?定義墨盒實現類(ColorInk和GrayInk)和紙張實現類(A3Paper和A4Paper)。
(4)?Spring配置文件,先配置彩色墨盒和黑白墨盒,然后配置A3紙和A4紙,最后配置打印機,使用設值方式在打印機中注入墨盒和紙張。
(5)?編寫測試類輸出打印機信息。
?
3:?使用構造注入重新組裝打印機
訓練技能點
?Spring構造注入
需求說明
任務實訓1的基礎上,使用構造注入重新組裝打印機。
實現思路
(1)?在Printer類中增加帶參構造方法。
(2)?修改配置文件,改為構造注入。
4:?使用ByName自動注入重新組裝打印機
訓練技能點
?Spring自動注入
需求說明
升級實訓任務3,打印機包括硬盤、顯示器、電源,要求使用Spring程序組裝打印機,并輸出打印機的配置信息。
實現思路
(1)?添加電源類Power,該類有一個方法printPowerInfo(),用于輸出電源信息。
(2)?修改配置文件為ByName自動注入。
(3)?編寫測試類進行測試。
關鍵代碼
(1)?編寫電源類:
public class Power {
private String type;// 電源型號
public void printPowerInfo() {
System.out.println("電源:" + type);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
(2)?在打印機類中增加屬性:
private Power power;// 電源
public Power getPower() {
return power;
}
public void setPower(Power power) {
this.power = power;
}
(3)?修改Spring配置文件,添加以下配置:
<bean id="power" class="bean.Power">
??<property name="type">
<value>長城</value>
??</property>
</bean>
<bean id="printer" class="bean.Printer" autowire="byName">
5:?使用Spring管理部門對象
訓練技能點
?list元素的使用
需求說明
某公司銷售部有三名員工,請編寫Spring程序輸出銷售部的部門名稱、該部門所有員工的員工姓名和員工地址。要求使用集合元素實現該需求。
實現思路
(1)?創建EmpVo類和DeptVo類。
(2)?DeptVo類中定義List集合屬性emps。
(3)?配置Spring文件。
(4)?編寫測試類,輸出給部門詳細信息。
關鍵代碼
(1)?員工信息包括員工姓名和員工地址,我們可以在員工類中增加員工姓名屬性和員工地址屬性。
public class EmpVo {
private String name;//員工名稱
private String adress;//員工地址
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
}
部門中可以包含多個員工,我們可以在部門類中增加兩個屬性,分別是部門名稱和部門員工集合,關鍵代碼如下所示。
private String deptName;// 部門名稱
private List emps;// 部門員工集合
(2)?編寫Spring配置文件,對部門的配置如下所示。
<bean id="dept" class="bean.DeptVo">
<property name="deptName">
<value>銷售部</value>
</property>
<property name="emps">
<list>
<ref bean="emp0" />
<ref bean="emp1" />
</list>
????????</property>
</bean>
鞏固練習
?
一.選擇題
1. 有關Spring,以下說法錯誤的是()。
???A. Spring是一個輕量級框架。
???B. Spring提供依賴注入容器、AOP實現、DAO/ORM支持、Web集成等功能。
???C. Spring的目標是使現有的技術變的更加好用。
???D. Spring不支持自動注入。
2. 以下關于依賴注入的選項中,說法正確的是()。
???A. 依賴注入的目標是在代碼之外管理程序組件間的依賴關系
???B. 依賴注入就是“面向切面編程”
???C. 依賴注入是面向對象技術的替代品
???D. 依賴注入會增大程序的規模
3. 關于IOC的理解,以下說法正確的是()。
???A. 控制反轉
???B. 對象被動接受依賴類
???C. 對象主動尋找依賴類
???D. 必須使用接口
4. 下列選項中,屬于Spring依賴注入方式的是()。
???A. set方法注入
???B. 構造方法注入
???C. get方法注入
???D. 接口注入
5. 以下關于在Spring中配置Bean的id屬性的說法中,正確的是()。
???A. id屬性值可以重復
???B. id屬性值不可以重復
???C. id屬性是必需的,沒有id屬性時會報鍺
D. id屬性不是必需的
6. 下列哪一個注解用于聲明一個bean()。
???A. @Resource
???B. @Component
???C. @Scope
D. @Qualifier
7. 下列關于使用注解來進行依賴注入的描述正確的是()。
???A. ?@Autowired?默認按 byType 自動注入依賴
B. @Autowired?默認按 byName 自動注入依賴
???C. @Resource?默認按?byType 自動注入依賴
D. @Resource?默認按?byName 自動注入依賴
?
二.操作題
1.某程序系統中有如下幾個類。
public class Equip {//裝備
private String name;//裝備名稱
private String type;//裝備類型,頭盔、鎧甲等
private Long speedPlus;//速度增效
private Long attackPlus;//攻擊增效
private Long defencePlus;//防御增效
//Getters & Setters
. . .
}
public class Player {// 玩家
private Equip armet;// 頭盔
private Equip loricae;// 鎧甲
private Equip boot;// 靴子
private Equip ring;// 指環
// Getters & Setters
public void updateEquip(Equip equip) {
if ("頭盔".equals(equip.getType())) {
System.out.println(armet.getName() + "升級為" + equip.getName());
this.armet = equip;
}
???. . .
}
}
根據以上信息,使用Spring DI配置一個擁有如下裝備的玩家,如表1-3-1所示。
表1-3-1 裝備信息
| 裝備 | 戰神頭盔 | 連環鎖子甲 | 波斯追風靴 | 藍魔指環 |
| 速度增效 | 2 | 6 | 8 | 8 |
| 攻擊增效 | 4 | 4 | 2 | 12 |
| 防御增效 | 6 | 15 | 3 | 2 |
?
2.編寫一個程序,實現對員工信息的CURD,要求DAO類中編寫5個方法:
get(int id)、save(EmpVo emp)、delete(int id)、update(EmpVo emp)、findAll()方法,編寫BIZ類,BIZ類中一個方法:doUpdate(EmpVo emp),方法功能為指定編號的員工如果存在,把薪水在原有基礎上增加500;如果不存在,則提示該員工不存在,更改失敗。使用Spring管理DAO和BIZ,并從Spring容器中獲取BIZ實例進行測試。
提示:創建EmpBiz接口和實現類,在實現類中增加DAO屬性。
public class EmpBizImpl implements EmpBiz {
private EmpDAO empDAO;
public void doUpdate(EmpVo emp)
{
//調用DAO類方法操作
}
//setter & getter
}
3.?自從世界上出現飛機以來,飛機的結構形式雖然在不斷改進,飛機類型不斷增多,但到目前為止,除了極少數特殊形式的飛機之外,大多數飛機都是由下面六個主要部分組成,即:兩支機翼、一個機身、兩支尾翼、一個起落裝置、一個操縱系統和四個動力裝置。請使用Spring的依賴注入組裝一架飛機。
提示:
編寫六個接口,分別對應機翼、機身、尾翼、起落裝置、操縱系統、動力裝置。在飛機類中增加兩個機翼屬性,分別表示左機翼和右機翼,尾翼和動力裝置采用相同的處理。
?
4.移動公司某營業點需要一個會員賬戶管理系統,該系統需要實現以下功能
(1)顯示所有會員賬戶信息。
(2)為指定的會員賬戶充值。
(3)刪除指定的賬戶。
(4)禁用或者啟用指定的賬戶。
(5)根據狀態查詢會員賬戶。
系統首頁參考界面如圖1.3.1所示:
轉存失敗重新上傳取消
圖1.3.1 賬戶管理系統首頁
當點擊“充值”時,如果該會員狀態為禁用狀態,則給出“禁用狀態的會員不能充值”提示,點擊“啟用”可以將會員狀態更改為“啟用狀態”。參考界面如圖1.3.2。
轉存失敗重新上傳取消
圖1.3.2 充值失敗提示
會員充值界面如圖1.3.3所示。
轉存失敗重新上傳取消
圖1.3.3會員充值界面
當會員充值成功之后,系統跳轉至首頁,顯示當前最新會員信息。
點擊“刪除”將刪除會員信息,刪除成功之后,系統首頁將顯示最新的會員信息。
請根據以上需求完成以下內容:
該系統的數據庫設計,DAO層的編寫,業務邏輯層的實現,并使用Spring管理業務邏輯層對象。
提示:
在業務邏輯層增加DAO類屬性,使用Spring在Biz中注入DAO,編寫測試代碼,對Biz中方法進行測試,不需要WEB層的開發。
總結
以上是生活随笔為你收集整理的Spring入门 IOC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电子商务之 网店客服中心服务用语规范
- 下一篇: Spring面向切面编程