“你用過什么框架?我用過Srping,但不要說成我用過春!”,哈哈。剛開課,佟佟就把大家斗樂了,非常開心。佟佟這稱號是同學私底下叫的,比較親切。他無論在哪個班上課,都可以聽到那個班的歡聲笑語。
大名鼎鼎的Spring大家都聽過,spring是一個開源框架,Spring為簡化企業級應用開發而生。使用Spring可以使簡單的JavaBean實現以前只有EJB才能實現的功能。Spring是一個DI(依賴注入)和AOP(面向切面編程)容器框架。
Spring具體應用細節,以及與struts和hibernater的整合。我們還沒有學習到,今天算是Spring的基礎操作和實現IOC(控制反轉)以及DI(依賴注入)的原理。
從JavaWEB基礎學習過來的,IOC和DI的實現原理非常簡單,雖然他們的名字響亮。他們的實現原理,我在來傳智播客之前就已經了解了:http://user.qzone.qq.com/252796718/infocenter?ptlang=2052&ADUIN=252796718&ADSESSION=1264331746&ADTAG=CLIENT.QQ.2707_Mysrv.0 。
Let's begin!
一、spring框架
Spring 框架是一個分層架構,由 7 個定義良好的模塊組成。Spring 模塊構建在核心容器之上,核心容器定義了創建、配置和管理 bean 的方式,如圖 1 所示。
Spring框架概述
組成 Spring 框架的每個模塊(或組件)都可以單獨存在,或者與其他一個或多個模塊聯合實現。每個模塊的功能如下:
· 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉 (IOC) 模式將應用程序的配置和依賴性規范與實際的應用程序代碼分開。
· Spring 上下文:Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。
· Spring AOP:通過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對象支持 AOP。Spring AOP 模塊為基于 Spring 的應用程序中的對象提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務管理集成到應用程序中。
· Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,并且極大地降低了需要編寫的異常代碼數量(例如打開和關閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
· Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
· Spring Web 模塊:Web 上下文模塊建立在應用程序上下文模塊之上,為基于 Web 的應用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。
· Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 框架的功能可以用在任何 J2EE 服務器中,大多數功能也適用于不受管理的環境。Spring 的核心要點是:支持不綁定到特定 J2EE 服務的可重用業務和數據訪問對象。毫無疑問,這樣的對象可以在不同 J2EE 環境 (Web 或 EJB)、獨立應用程序、測試環境之間重用。
我們今天的重點內容是——核心容器。
二、HelloSpring
這個“HelloWorld!”的經典程序,還要引領多長時間?可能會一直下去吧。我們現在就開始編寫一個Spring的HelloWorld!程序,來學習一下Spring環境的搭建。
1.安裝Spring的Eclipse插件。
2.新建立一個Java工程,在工程上右鍵->Spring Tools->Add Spring Project Nature。
3.導入“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的區別不是很大。
4.在工程中添加“HelloSpring.java”:
package cn.itcast.cc.spring; public class HelloSpring { private String message; // 構造函數 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”目錄下,新建一個“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"> <!-- 描述一個Bean,name指定Bean的名稱,class指定Bean類名 --> <bean name="helloSpring" class="cn.itcast.cc.spring.HelloSpring"> <!-- property設置屬性值,name指定名稱,value指定屬性值 --> <property name="message" value="**Spring**" /> </bean> </beans> |
6.添加測試類:
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) { // 創建應用程序環境 ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml"); // 獲取名稱為helloSpring的Bean HelloSpring hs = (HelloSpring) appCon.getBean("helloSpring"); // 調用Bean的方法 hs.hello(); } } |
7.控制臺輸出:
指定Bean的名稱,可以使用name,也可以使用id。一般情況下建議使用id,因為id在XML文件中是一個特殊的屬性,XML會自動校驗ID的唯一性。
可能通過屬性的setter方法或著Bean的構造函數設置屬性的值,但setter是比較常用的。使用構造函數設置屬性的值,使用“<constructor-arg value="**Spring**"/>”替換“property”元素。注意一定要有與之對應的構造方法。
從剛開始的Dao接口到工廠模式再到Spring框架,都是為了實現更好的解耦。
三、Spring的配置文件
1.引用Bean
在應用中經常會遇見一個Bean實體,將另一個Bean實體做為自己的屬性。那么這個屬性值我們在XML文件中應該如何指定呢?Property有一個ref屬性,ref屬性的值設置為指定Bean元素的名稱即可。
2.內部Bean
當一個Bean實體只被用作另一個Bean的屬性時。我們可以將這個Bean聲明為內部Bean。內部Bean無須設置它的id或name值,它被做為子元素嵌入在對應property元素中。
3.繼承式Bean
bean元素中“depends-on”屬性用來指定父類。
Spring 允許將通用的 Bean 配置抽象出來, 組成一個父 Bean。 繼承這個父 Bean 的 Bean 稱為子 Bean。
子 Bean 從父 Bean 中繼承配置, 包括 Bean 的屬性和在 <bean> 元素里的屬性。
子 Bean 也可以覆蓋從父 Bean 繼承過來的配置。
父 Bean 可以作為配置模板, 也可以作為 Bean 實例。 若只想把父 Bean 作為模板, 可以設置 <bean> 的abstract 屬性為 true, 這樣 Spring 將不會實例化這個 Bean。
并不是 <bean> 元素里的所有屬性都會被繼承。 比如: autowire, dependency-check, abstract 等。
也可以忽略父 Bean 的 class 屬性, 讓子 Bean 指定自己的類, 而共享相同的屬性配置。 但此時 abstract 必須設為 true。
4.設置集合屬性
經常見到Bean具有集合屬性,在hibernate的XML文件中也可以設置集合屬性的值。
在 Spring 中可以通過一組內置的 xml 標簽(例如: <list>, <set> 或 <map>) 來配置集合屬性。
需求: 序列號生成器需要使用多個后綴。 這些后綴使用 “-” 作為分割, 附加在序列號后邊。 這些后綴可以是任意的數據類型, 在拼接時將它們轉換為字符串。
也可以使用“utility scheme”工具,定義可重用的集合設置,引時xml文件需要引入特定的標簽庫,參照下面的內容。
5.檢查屬性
設置Bean的“dependency-check="objects"”屬性,檢查bean中的所有屬性是否通過setter方法注入了值。如果是通過構造方法注入,或沒有注入都會拋異常。Dependency-check不檢查屬性值是否合法。
在bean中設置“dependency-check="objects"”屬性,它會檢查所有屬性。如果我們想要檢查某一個屬性怎么辦?首先添加一個:
HelloSpring,Construct! Hello:**Spring** |
或
使用“<context:annotation-config />”時,beans的元素屬性內容為:
<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將檢查被標“@Required”注解的屬性。
如果使用的是JRE1.5需要添加“spring-framework-2.5.6.SEC01\lib\j2ee\common-annotations.jar”jar。
6.Bean 自動裝配
Spring IOC 容器可以幫助自動裝配 Bean。需要做的僅僅是在 <bean> 的 autowire 屬性里指定自動裝配的模式。
byType(根據類型自動裝配): 若IOC 容器中有多個與目標Bean類型一致的Bean。在這種情況下, Spring 將無法判定哪個Bean最合適該屬性,所以不能執行自動裝配。
byName(根據名稱自動裝配): 必須將目標Bean的名稱和屬性名設置的完全相同。
constructor(通過構造器自動裝配): 當Bean中存在多個構造器時, 此種自動裝配方式將會很復雜。 不推薦使用。
四、Spring的注解
通過Xml文件配置應用程序是之前流行的方式,但不夠直觀和便利。現在流行使用注解了。在Spring2.5(包括2.5)之后就開始支持注解了。
使用注解時,我們只需要將Spring的配置文件內容設置為:
<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”: 基本注解, 標識了一個受 Spring 管理的組件。
“@Respository”: 標識持久層組件。
“@Service”: 標識服務層(業務層)組件。
“@Controller”: 標識表現層組件。
“@Autowired”自動裝配具有兼容類型的單個 Bean屬性。默認情況下, 所有使用 @Authwired 注解的屬性都需要被設置。 當 Spring 找不到匹配的 Bean 裝配屬性時, 會拋出異常, 若某一屬性允許不被設置, 可以設置 @Authwired 注解的 required 屬性為 false。
構造器, 普通字段(即使是非 public), 一切具有參數的方法都可以應用 @Authwired 注解。
它可以應用在數組類型的屬性上, 此時 Spring 將會把所有匹配的 Bean 進行自動裝配。
它可以應用在集合屬性上, 此時 Spring 讀取該集合的類型信息, 然后自動裝配所有與之兼容的 Bean。
它用在 java、util、Map上時, 若該 Map 的鍵值為 String, 那么 Spring 將自動裝配與之 Map 值類型兼容的 Bean, 此時 Bean 的名稱作為鍵值。
默認情況下, 當 IOC 容器里存在多個類型兼容的 Bean 時, 通過類型的自動裝配將無法工作。 此時可以在 @Qualifier 注解里提供 Bean 的名稱。但該注解只能用于修飾字段, 不能用于修飾方法
“@Resource”通過名稱自動裝配 Bean 屬性,若沒有名稱一致的裝配類型一致的。
構造器, 普通字段(即使是非 public), 一切具有參數的方法都可以應用@ Resource 注解。
默認情況下,Spring將試著找出和屬性名稱相同的Bean。也可以在@Resource注解的name屬性里指定 Bean 的名稱。
五、Spring高級特性
1.Bean的作用域
如果不為指定Bean的作用域,Spring默認(scope="singleton")只維護一個Bean實例,所有調用同一getBean(name)的位置都返回同一實例。設置Bean的作用域為“scope="property"”Spring都返回一個對應Bean的新的實例。
2.Bean的初始化和銷毀過程
在企業開發中,組件在使用之前往往需要執行一些特定類型的初始化任務,其中包括打開文件,打開網絡/數據庫連接,分配內存等。同樣,當組件結束其生命周期時,也需要執行與之對應的銷毀任務。
設置Bean的初始化和銷毀過程?!?/font>@PostConstruct”調用Bean的初始化過程,當Bean創建后并設置屬性值后會調標注了此注解的方法。“@PreDestroy”調用Bean的銷毀過程,當Bean被銷前會調用標注了此注解的方法。
注意:當Spring只維護一個Bean實例時,Bean被銷前會調用標注了“@PreDestroy”注解的方法,否則不會調用。
3.Bean 后置處理器
Bean后置處理器允許在調用初始化方法前后對Bean進行額外的處理。
Bean后置處理器對IOC容器里的所有Bean實例逐一處理,而非單一實例。其典型應用是:檢查Bean屬性的正確性或根據特定的標準更改Bean的屬性。
對Bean后置處理器而言,需要實現接口“BeanPostProcessor”。在初始化方法被調用前后,Spring將把每個Bean實例分別傳遞給上述接口的以下兩個方法:
“postProcessAfterInitialization”和“postProcessBeforeInitialization”。
SpringIOC容器對Bean的生命周期進行管理的過程:
1).通過構造器或工廠方法創建Bean實例
2).為Bean的屬性設置值和對其他Bean的引用
3).將Bean實例傳遞給Bean后置處理器的postProcessBeforeInitialization方法
4).調用Bean的初始化方法
5).將Bean實例傳遞給Bean后置處理器的postProcessAfterInitialization方法
6).Bean可以使用了
7).當容器關閉時,調用Bean的銷毀方法
注冊Bean后置處理器,只需要在配置文件里聲明聲明一個該處理器的實例,ApplicationContext會探測到實現了BeanPostProcessor接口的Bean并進行注冊。
若初始化和銷毀方法是通過添加生命周期注解@PostConstructor和@PreDestory實現的,則自定義的Bean后置處理器將無法工作。其原因是CommonAnnotationBeanPostProcessor的優先級比自定義的Bean后置處理器的優先級高。結果在對路徑檢查之前初始化方法已經被調用。
要定義Bean后置處理器的處理順序,需要讓Bean后置處理器的實例實現Ordered或者PriorityOrdered接口,在getOrder()方法中返回順序值。該方法返回的數值越低優先級越高。另:PriorityOrdered接口返回的順序值總優先于Ordered接口返回的順序值,而CommonAnnotationBeanPostProcessor實現了PriorityOrdered接口。
4.外部化Bean的配置
在配置文件里配置Bean時,有時需要在Bean的配置里混入系統部署的細節信息(例如:文件路徑,數據源配置信息等)。而這些部署細節實際上需要和Bean配置相分離。
Spring提供了一個PropertyPlaceholderConfigurer的BeanFactory后置處理器,這個處理器允許用戶將Bean配置的部分內容外移到屬性文件中??梢栽?/font>Bean配置文件里使用形式為${var}的變量,PropertyPlaceholderConfigurer從屬性文件里加載屬性,并使用這些屬性來替換變量。
在Spring2.0中注冊PropertyPlaceholderConfigurer:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="c3p0.properties" /> </bean> |
在Spring2.5中可通過<context:property-placeholder>,簡化注冊PropertyPlaceholderConfigurer:
<context:property-placeholder location="classpath:c3p0.properties"/> |
此時beans的屬性內容為:
<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}的變量對應屬性文件(*.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> |
感覺東西越學越簡單了,好!
加油!