“你用過什么框架?我用過Srping,但不要說成我用過春!”,哈哈。剛開課,佟佟就把大家斗樂了,非常開心。佟佟這稱號(hào)是同學(xué)私底下叫的,比較親切。他無論在哪個(gè)班上課,都可以聽到那個(gè)班的歡聲笑語。
大名鼎鼎的Spring大家都聽過,spring是一個(gè)開源框架,Spring為簡(jiǎn)化企業(yè)級(jí)應(yīng)用開發(fā)而生。使用Spring可以使簡(jiǎn)單的JavaBean實(shí)現(xiàn)以前只有EJB才能實(shí)現(xiàn)的功能。Spring是一個(gè)DI(依賴注入)和AOP(面向切面編程)容器框架。
Spring具體應(yīng)用細(xì)節(jié),以及與struts和hibernater的整合。我們還沒有學(xué)習(xí)到,今天算是Spring的基礎(chǔ)操作和實(shí)現(xiàn)IOC(控制反轉(zhuǎn))以及DI(依賴注入)的原理。
從JavaWEB基礎(chǔ)學(xué)習(xí)過來的,IOC和DI的實(shí)現(xiàn)原理非常簡(jiǎn)單,雖然他們的名字響亮。他們的實(shí)現(xiàn)原理,我在來傳智播客之前就已經(jīng)了解了:http://user.qzone.qq.com/252796718/infocenter?ptlang=2052&ADUIN=252796718&ADSESSION=1264331746&ADTAG=CLIENT.QQ.2707_Mysrv.0 。
Let's begin!
一、spring框架
Spring 框架是一個(gè)分層架構(gòu),由 7 個(gè)定義良好的模塊組成。Spring 模塊構(gòu)建在核心容器之上,核心容器定義了創(chuàng)建、配置和管理 bean 的方式,如圖 1 所示。

Spring框架概述
組成 Spring 框架的每個(gè)模塊(或組件)都可以單獨(dú)存在,或者與其他一個(gè)或多個(gè)模塊聯(lián)合實(shí)現(xiàn)。每個(gè)模塊的功能如下:
· 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實(shí)現(xiàn)。BeanFactory 使用控制反轉(zhuǎn) (IOC) 模式將應(yīng)用程序的配置和依賴性規(guī)范與實(shí)際的應(yīng)用程序代碼分開。
· Spring 上下文:Spring 上下文是一個(gè)配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業(yè)服務(wù),例如 JNDI、EJB、電子郵件、國際化、校驗(yàn)和調(diào)度功能。
· Spring AOP:通過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對(duì)象支持 AOP。Spring AOP 模塊為基于 Spring 的應(yīng)用程序中的對(duì)象提供了事務(wù)管理服務(wù)。通過使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務(wù)管理集成到應(yīng)用程序中。
· Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結(jié)構(gòu),可用該結(jié)構(gòu)來管理異常處理和不同數(shù)據(jù)庫供應(yīng)商拋出的錯(cuò)誤消息。異常層次結(jié)構(gòu)簡(jiǎn)化了錯(cuò)誤處理,并且極大地降低了需要編寫的異常代碼數(shù)量(例如打開和關(guān)閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結(jié)構(gòu)。
· Spring ORM:Spring 框架插入了若干個(gè) ORM 框架,從而提供了 ORM 的對(duì)象關(guān)系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務(wù)和 DAO 異常層次結(jié)構(gòu)。
· Spring Web 模塊:Web 上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于 Web 的應(yīng)用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡(jiǎn)化了處理多部分請(qǐng)求以及將請(qǐng)求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?/font>
· Spring MVC 框架:MVC 框架是一個(gè)全功能的構(gòu)建 Web 應(yīng)用程序的 MVC 實(shí)現(xiàn)。通過策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術(shù),其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 框架的功能可以用在任何 J2EE 服務(wù)器中,大多數(shù)功能也適用于不受管理的環(huán)境。Spring 的核心要點(diǎn)是:支持不綁定到特定 J2EE 服務(wù)的可重用業(yè)務(wù)和數(shù)據(jù)訪問對(duì)象。毫無疑問,這樣的對(duì)象可以在不同 J2EE 環(huán)境 (Web 或 EJB)、獨(dú)立應(yīng)用程序、測(cè)試環(huán)境之間重用。
我們今天的重點(diǎn)內(nèi)容是——核心容器。
二、HelloSpring
這個(gè)“HelloWorld!”的經(jīng)典程序,還要引領(lǐng)多長(zhǎng)時(shí)間?可能會(huì)一直下去吧。我們現(xiàn)在就開始編寫一個(gè)Spring的HelloWorld!程序,來學(xué)習(xí)一下Spring環(huán)境的搭建。
1.安裝Spring的Eclipse插件。
2.新建立一個(gè)Java工程,在工程上右鍵->Spring Tools->Add Spring Project Nature。
3.導(dǎo)入“spring-framework-2.5.6.SEC01\dist\spring.jar”和“spring-framework-2.5.6.SEC01\lib\jakarta-commons\commons-logging.jar”。我們使用的Spring的版本是2.5,3.0剛剛出來。但3.0與2.5的區(qū)別不是很大。
4.在工程中添加“HelloSpring.java”:
package cn.itcast.cc.spring; public class HelloSpring { private String message; // 構(gòu)造函數(shù) public HelloSpring() { System.out.println("HelloSpring,Construct!"); } // Spring通過此方法注入屬性值 public void setMessage(String message) { this.message = message; } // 打印消息 public void hello() { System.out.println("Hello:" + this.message); } } |
5.在“src”目錄下,新建一個(gè)“applicationContext.xml”文件。(在“src”目錄上右鍵->New->Other->Spring->Spring Bean Definition):
<?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.xsd"> <!-- 描述一個(gè)Bean,name指定Bean的名稱,class指定Bean類名 --> <bean name="helloSpring" class="cn.itcast.cc.spring.HelloSpring"> <!-- property設(shè)置屬性值,name指定名稱,value指定屬性值 --> <property name="message" value="**Spring**" /> </bean> </beans> |
6.添加測(cè)試類:
package cn.itcast.cc.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { // 創(chuàng)建應(yīng)用程序環(huán)境 ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml"); // 獲取名稱為helloSpring的Bean HelloSpring hs = (HelloSpring) appCon.getBean("helloSpring"); // 調(diào)用Bean的方法 hs.hello(); } } |
7.控制臺(tái)輸出:
指定Bean的名稱,可以使用name,也可以使用id。一般情況下建議使用id,因?yàn)?/font>id在XML文件中是一個(gè)特殊的屬性,XML會(huì)自動(dòng)校驗(yàn)ID的唯一性。
可能通過屬性的setter方法或著Bean的構(gòu)造函數(shù)設(shè)置屬性的值,但setter是比較常用的。使用構(gòu)造函數(shù)設(shè)置屬性的值,使用“<constructor-arg value="**Spring**"/>”替換“property”元素。注意一定要有與之對(duì)應(yīng)的構(gòu)造方法。
從剛開始的Dao接口到工廠模式再到Spring框架,都是為了實(shí)現(xiàn)更好的解耦。
三、Spring的配置文件
1.引用Bean
在應(yīng)用中經(jīng)常會(huì)遇見一個(gè)Bean實(shí)體,將另一個(gè)Bean實(shí)體做為自己的屬性。那么這個(gè)屬性值我們?cè)?/font>XML文件中應(yīng)該如何指定呢?Property有一個(gè)ref屬性,ref屬性的值設(shè)置為指定Bean元素的名稱即可。
2.內(nèi)部Bean
當(dāng)一個(gè)Bean實(shí)體只被用作另一個(gè)Bean的屬性時(shí)。我們可以將這個(gè)Bean聲明為內(nèi)部Bean。內(nèi)部Bean無須設(shè)置它的id或name值,它被做為子元素嵌入在對(duì)應(yīng)property元素中。
3.繼承式Bean
bean元素中“depends-on”屬性用來指定父類。
Spring 允許將通用的 Bean 配置抽象出來, 組成一個(gè)父 Bean。 繼承這個(gè)父 Bean 的 Bean 稱為子 Bean。
子 Bean 從父 Bean 中繼承配置, 包括 Bean 的屬性和在 <bean> 元素里的屬性。
子 Bean 也可以覆蓋從父 Bean 繼承過來的配置。
父 Bean 可以作為配置模板, 也可以作為 Bean 實(shí)例。 若只想把父 Bean 作為模板, 可以設(shè)置 <bean> 的abstract 屬性為 true, 這樣 Spring 將不會(huì)實(shí)例化這個(gè) Bean。
并不是 <bean> 元素里的所有屬性都會(huì)被繼承。 比如: autowire, dependency-check, abstract 等。
也可以忽略父 Bean 的 class 屬性, 讓子 Bean 指定自己的類, 而共享相同的屬性配置。 但此時(shí) abstract 必須設(shè)為 true。
4.設(shè)置集合屬性
經(jīng)常見到Bean具有集合屬性,在hibernate的XML文件中也可以設(shè)置集合屬性的值。
在 Spring 中可以通過一組內(nèi)置的 xml 標(biāo)簽(例如: <list>, <set> 或 <map>) 來配置集合屬性。
需求: 序列號(hào)生成器需要使用多個(gè)后綴。 這些后綴使用 “-” 作為分割, 附加在序列號(hào)后邊。 這些后綴可以是任意的數(shù)據(jù)類型, 在拼接時(shí)將它們轉(zhuǎn)換為字符串。
也可以使用“utility scheme”工具,定義可重用的集合設(shè)置,引時(shí)xml文件需要引入特定的標(biāo)簽庫,參照下面的內(nèi)容。
5.檢查屬性
設(shè)置Bean的“dependency-check="objects"”屬性,檢查bean中的所有屬性是否通過setter方法注入了值。如果是通過構(gòu)造方法注入,或沒有注入都會(huì)拋異常。Dependency-check不檢查屬性值是否合法。
在bean中設(shè)置“dependency-check="objects"”屬性,它會(huì)檢查所有屬性。如果我們想要檢查某一個(gè)屬性怎么辦?首先添加一個(gè):
HelloSpring,Construct! Hello:**Spring** |
或
使用“<context:annotation-config />”時(shí),beans的元素屬性內(nèi)容為:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" /> |
<context:annotation-config /> |
<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" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd "> |
然后在Bean的setter方法上添加“@Required”注解,這樣Spring將檢查被標(biāo)“@Required”注解的屬性。
如果使用的是JRE1.5需要添加“spring-framework-2.5.6.SEC01\lib\j2ee\common-annotations.jar”jar。
6.Bean 自動(dòng)裝配
Spring IOC 容器可以幫助自動(dòng)裝配 Bean。需要做的僅僅是在 <bean> 的 autowire 屬性里指定自動(dòng)裝配的模式。
byType(根據(jù)類型自動(dòng)裝配): 若IOC 容器中有多個(gè)與目標(biāo)Bean類型一致的Bean。在這種情況下, Spring 將無法判定哪個(gè)Bean最合適該屬性,所以不能執(zhí)行自動(dòng)裝配。
byName(根據(jù)名稱自動(dòng)裝配): 必須將目標(biāo)Bean的名稱和屬性名設(shè)置的完全相同。
constructor(通過構(gòu)造器自動(dòng)裝配): 當(dāng)Bean中存在多個(gè)構(gòu)造器時(shí), 此種自動(dòng)裝配方式將會(huì)很復(fù)雜。 不推薦使用。
四、Spring的注解
通過Xml文件配置應(yīng)用程序是之前流行的方式,但不夠直觀和便利。現(xiàn)在流行使用注解了。在Spring2.5(包括2.5)之后就開始支持注解了。
使用注解時(shí),我們只需要將Spring的配置文件內(nèi)容設(shè)置為:
<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" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd "> <context:annotation-config /> </beans> |
“@Component”: 基本注解, 標(biāo)識(shí)了一個(gè)受 Spring 管理的組件。
“@Respository”: 標(biāo)識(shí)持久層組件。
“@Service”: 標(biāo)識(shí)服務(wù)層(業(yè)務(wù)層)組件。
“@Controller”: 標(biāo)識(shí)表現(xiàn)層組件。
“@Autowired”自動(dòng)裝配具有兼容類型的單個(gè) Bean屬性。默認(rèn)情況下, 所有使用 @Authwired 注解的屬性都需要被設(shè)置。 當(dāng) Spring 找不到匹配的 Bean 裝配屬性時(shí), 會(huì)拋出異常, 若某一屬性允許不被設(shè)置, 可以設(shè)置 @Authwired 注解的 required 屬性為 false。
構(gòu)造器, 普通字段(即使是非 public), 一切具有參數(shù)的方法都可以應(yīng)用 @Authwired 注解。
它可以應(yīng)用在數(shù)組類型的屬性上, 此時(shí) Spring 將會(huì)把所有匹配的 Bean 進(jìn)行自動(dòng)裝配。
它可以應(yīng)用在集合屬性上, 此時(shí) Spring 讀取該集合的類型信息, 然后自動(dòng)裝配所有與之兼容的 Bean。
它用在 java、util、Map上時(shí), 若該 Map 的鍵值為 String, 那么 Spring 將自動(dòng)裝配與之 Map 值類型兼容的 Bean, 此時(shí) Bean 的名稱作為鍵值。
默認(rèn)情況下, 當(dāng) IOC 容器里存在多個(gè)類型兼容的 Bean 時(shí), 通過類型的自動(dòng)裝配將無法工作。 此時(shí)可以在 @Qualifier 注解里提供 Bean 的名稱。但該注解只能用于修飾字段, 不能用于修飾方法
“@Resource”通過名稱自動(dòng)裝配 Bean 屬性,若沒有名稱一致的裝配類型一致的。
構(gòu)造器, 普通字段(即使是非 public), 一切具有參數(shù)的方法都可以應(yīng)用@ Resource 注解。
默認(rèn)情況下,Spring將試著找出和屬性名稱相同的Bean。也可以在@Resource注解的name屬性里指定 Bean 的名稱。
五、Spring高級(jí)特性
1.Bean的作用域
如果不為指定Bean的作用域,Spring默認(rèn)(scope="singleton")只維護(hù)一個(gè)Bean實(shí)例,所有調(diào)用同一getBean(name)的位置都返回同一實(shí)例。設(shè)置Bean的作用域?yàn)椤?/font>scope="property"”Spring都返回一個(gè)對(duì)應(yīng)Bean的新的實(shí)例。
2.Bean的初始化和銷毀過程
在企業(yè)開發(fā)中,組件在使用之前往往需要執(zhí)行一些特定類型的初始化任務(wù),其中包括打開文件,打開網(wǎng)絡(luò)/數(shù)據(jù)庫連接,分配內(nèi)存等。同樣,當(dāng)組件結(jié)束其生命周期時(shí),也需要執(zhí)行與之對(duì)應(yīng)的銷毀任務(wù)。
設(shè)置Bean的初始化和銷毀過程。“@PostConstruct”調(diào)用Bean的初始化過程,當(dāng)Bean創(chuàng)建后并設(shè)置屬性值后會(huì)調(diào)標(biāo)注了此注解的方法。“@PreDestroy”調(diào)用Bean的銷毀過程,當(dāng)Bean被銷前會(huì)調(diào)用標(biāo)注了此注解的方法。
注意:當(dāng)Spring只維護(hù)一個(gè)Bean實(shí)例時(shí),Bean被銷前會(huì)調(diào)用標(biāo)注了“@PreDestroy”注解的方法,否則不會(huì)調(diào)用。
3.Bean 后置處理器
Bean后置處理器允許在調(diào)用初始化方法前后對(duì)Bean進(jìn)行額外的處理。
Bean后置處理器對(duì)IOC容器里的所有Bean實(shí)例逐一處理,而非單一實(shí)例。其典型應(yīng)用是:檢查Bean屬性的正確性或根據(jù)特定的標(biāo)準(zhǔn)更改Bean的屬性。
對(duì)Bean后置處理器而言,需要實(shí)現(xiàn)接口“BeanPostProcessor”。在初始化方法被調(diào)用前后,Spring將把每個(gè)Bean實(shí)例分別傳遞給上述接口的以下兩個(gè)方法:
“postProcessAfterInitialization”和“postProcessBeforeInitialization”。
SpringIOC容器對(duì)Bean的生命周期進(jìn)行管理的過程:
1).通過構(gòu)造器或工廠方法創(chuàng)建Bean實(shí)例
2).為Bean的屬性設(shè)置值和對(duì)其他Bean的引用
3).將Bean實(shí)例傳遞給Bean后置處理器的postProcessBeforeInitialization方法
4).調(diào)用Bean的初始化方法
5).將Bean實(shí)例傳遞給Bean后置處理器的postProcessAfterInitialization方法
6).Bean可以使用了
7).當(dāng)容器關(guān)閉時(shí),調(diào)用Bean的銷毀方法
注冊(cè)Bean后置處理器,只需要在配置文件里聲明聲明一個(gè)該處理器的實(shí)例,ApplicationContext會(huì)探測(cè)到實(shí)現(xiàn)了BeanPostProcessor接口的Bean并進(jìn)行注冊(cè)。
若初始化和銷毀方法是通過添加生命周期注解@PostConstructor和@PreDestory實(shí)現(xiàn)的,則自定義的Bean后置處理器將無法工作。其原因是CommonAnnotationBeanPostProcessor的優(yōu)先級(jí)比自定義的Bean后置處理器的優(yōu)先級(jí)高。結(jié)果在對(duì)路徑檢查之前初始化方法已經(jīng)被調(diào)用。
要定義Bean后置處理器的處理順序,需要讓Bean后置處理器的實(shí)例實(shí)現(xiàn)Ordered或者PriorityOrdered接口,在getOrder()方法中返回順序值。該方法返回的數(shù)值越低優(yōu)先級(jí)越高。另:PriorityOrdered接口返回的順序值總優(yōu)先于Ordered接口返回的順序值,而CommonAnnotationBeanPostProcessor實(shí)現(xiàn)了PriorityOrdered接口。
4.外部化Bean的配置
在配置文件里配置Bean時(shí),有時(shí)需要在Bean的配置里混入系統(tǒng)部署的細(xì)節(jié)信息(例如:文件路徑,數(shù)據(jù)源配置信息等)。而這些部署細(xì)節(jié)實(shí)際上需要和Bean配置相分離。
Spring提供了一個(gè)PropertyPlaceholderConfigurer的BeanFactory后置處理器,這個(gè)處理器允許用戶將Bean配置的部分內(nèi)容外移到屬性文件中。可以在Bean配置文件里使用形式為${var}的變量,PropertyPlaceholderConfigurer從屬性文件里加載屬性,并使用這些屬性來替換變量。
在Spring2.0中注冊(cè)PropertyPlaceholderConfigurer:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="c3p0.properties" /> </bean> |
在Spring2.5中可通過<context:property-placeholder>,簡(jiǎn)化注冊(cè)PropertyPlaceholderConfigurer:
<context:property-placeholder location="classpath:c3p0.properties"/> |
此時(shí)beans的屬性內(nèi)容為:
<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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd "> |
${var}的變量對(duì)應(yīng)屬性文件(*.properties)中名稱為var的屬性值:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}"/> <property name="password" value="${password}"/> <property name="jdbcUrl" value="${url}"/> <property name="driverClass" value="${driver}"/> </bean> |
感覺東西越學(xué)越簡(jiǎn)單了,好!
加油!