一.IOC和DI
1.IOC(Inversion of Control)
其思想是反轉資源獲取的方向。傳統的資源查找方式要求組件向容器發起請求查找資源,作為回應,容器適時的返回資源;而應用了IOC之后,則是容器主動的將資源推送給它所管理的組件,組件所要做的僅是選擇一種合適的方式來接收資源。這種行為也被成為查找的被動形式。
2.DI(Dependency Injection)
IOC的另一種表達方式:即組件的一些預先定義好的方式(例如:setter方法)接受來自如容器的資源注入。相對于IOC而言,這種表述更直接。
3.IOC的前世今生
使用這樣一個需求,生成HTML或者PDF格式的不同類型的報表為例,說明IOC的演變。
①分離接口設計
②采用工廠模式
③采用反轉控制
二.spring配置bean
1.在spring的IOC容器里面配置Bean。
在xml文件中通過bean節點來配置bean
<bean id="helloWorld"
class="com.desperado.helloworld.HelloWorld >
</bean>
id:Bean的名稱。
- 在IOC容器中必須是唯一的.
- 若id沒有指定,Spring會自動將全限定性類名作為Bean名稱。
- id可以指定多個名字,名字之間可以用逗號、分號、或空格隔開。
2.Spring容器
- 在Spring IOC容器讀取Bean配置創建Bean實例之前,必須對它進行實例化。只有在容器實例化之后,才可以從IOC容器里面獲取Bean實例并使用。
- Spring提供了兩種類型的IOC容器實現
- BeanFactory:IOC容器的基本實現。
- ApplicationContext:提供了更多的高級特性,是BeanFactory的子接口。
- BeanFactory是Spring框架的基礎設施,面向Spring本身。ApplicationContext面向使用Spring框架的開發者,幾乎所有的應用場合都直接使用ApplicationContext而非底層的BeanFactory。
- 無論使用何種方式,配置文件是相同的。
3.ApplicationContext
- ApplicationContext的主要實現類:
- ClassPathXmlApplicationContext:從類路徑下面加載配置文件。
- FileSystemXmlApplicationContext:從文件系統中加載配置文件。
- ConfigurableApplicationContext擴展于ApplicationContext,新增加兩個主要方法:refresh()和close(),讓ApplicationContext具有啟動、刷新和關閉上下文的能力。
- ApplicationContext在初始化上下文時就實例化所有單例的Bean。
- WebApplicationContext是專門為WEB應用而準備的,它允許從相對于WEB根目錄的路徑中完成初始化工作.。
- 調用ApplicationContext的getBean()方法可以獲取到Bean。
4.依賴注入的三種方式
- 屬性注入
屬性注入即通過setter方法注入Bean的屬性值或依賴的對象。
屬性注入使用<property>元素,使用name屬性指定Bean的屬性名稱,value屬性或<value>子節點指定屬性值。
屬性注入是實際應用中最常用的注入方式。
<bean id="helloWorld" class="com.desperado.helloworld.HelloWorld">
<property name="userName" value="desperado"></property>
</bean>
- 構造器注入
通過構造方法注入Bean的屬性值或依賴的對象,它保證了Bean實例在實例化后就可以使用。
構造器注入在<constructor-arg>元素里聲明屬性,<constructor-arg>中沒有name屬性。- 按索引匹配入參
<bean id="car" class ="com.desperado.helloworld.Car">
<constructor-arg value="奧迪" index="0"></constructor-arg>
<constructor-arg value="奔馳" index="1"></constructor-arg>
<constructor-arg value="5000" index="2"></constructor-arg>
</bean>
- 按匹配參數注入
<bean id="car" class ="com.desperado.helloworld.Car">
<constructor-arg value="奧迪" type="java.lang.String"></constructor-arg>
<constructor-arg value="奔馳" type="java.lang.String"></constructor-arg>
<constructor-arg value="5000" type="java.lang.double"></constructor-arg>
</bean>
工廠方法注入(很少使用,不推薦)
-
注入屬性值細節
- 字面值:可用字符串表示的值,可以通過<value>元素標簽或value屬性進行注入。
- 基本數據類型及其封裝類、String等類型都可以采取字面值的注入。
- 若字面值中包含特殊字符,可以使用<![CDATA[]]把字面值包裹起來。
5. 引用其他Bean
- 組成應用程序的Bean經常需要相互協作以完成應用程序的功能,要使Bean能夠相互訪問,就必須在Bean配置文件中指定對Bean的引用。
- 在Bean的配置文件中,可以通過<ref>元素或ref屬性為Bean的屬性或構造器參數指定對Bean的引用。
- 也可以在屬性或構造器里包含Bean的聲明,這樣的Bean成為內部Bean。
<bean id="service" class="com.desperado.helloworld.Service"></bean>
<bean id="action" class="com.desperado.helloworld.Action">
<property name="service" ref="service"></property>
</bean>
6.內部bean
- 當Bean實例僅僅給一個特定的屬性使用時,可以將其聲明為內部Bean,內部Bean聲明直接包含在<property>或者<constructor-arg>元素里,不需要設置任何id或name屬性。
- 內部Bean不能使用在任何其他部分。
7.null值和級聯屬性
- 可以使用專用的<null />元素標簽為Bean的字符串或其它對象類型的屬性注入null值。
- Spring支持級聯屬性的配置。
8.集合屬性
- 在Spring中可以通過一組內置的xml標簽(例如<list>,<set>,<map>)來配置集合屬性。
- 配置java.util.List類型的屬性,需要指定<list>標簽,在標簽里包含一些元素。這些標簽可以通過<value>指定簡單的常量值。這些標簽可以通過<value>指定簡單的常量值,通過<ref>指定對其他Bean的引用。通過<bean>指定內置Bean的定義,通過<null/>指定空元素,甚至可以內嵌其他集合。
- 數組的定義和List一樣,都使用<list>
- 配置java.util.Set需要使用<set>標簽,定義元素的方法與List一樣。
- java.lang.Map通過<map>標簽定義,<map>標簽里可以使用多個<entry>作為子標簽,每個條目包含一個鍵和一個值。
- 必須在<key>標簽里定義鍵。
- 因為鍵和值的類型沒有限制,索引可以自由的為它們指定<value>,<ref>,<bean>或<null>元素。
- 可以將Map的鍵和值作為<entry>的屬性定義:簡單常量使用key和value定義;Bean引用通過key-ref和value-ref屬性定義。
- 使用<props>定義java.util.Properties,該標簽使用多個<prop>作為子標簽,每個<prop>標簽必須定義key屬性。
9.使用utility scheme定義集合
- 使用基本的集合標簽定義集合時,不能將集合作為獨立的Bean定義,導致其他Bean無法引用該集合,所以無法再不同Bean之間共享集合。
- 可以使用util schema里的集合標簽定義獨立的集合Bean。需要注意的是,必須在<beans>根元素里添加util schema定義。
10.使用P命名空間
- 為了將XML文件的配置越來越多的XML文件采用屬性而非子元素配置信息。
- Spring從2.5開始引入了一個新的p命名空間,可以通過<bean>元素屬性的方式配置Bean的屬性。
-使用p命名空間后,基于XML的配置方式將進一步簡化。
三.XML配置里的Bean自動裝配
- Spring IOC容器可以自動裝配Bean,需要做的僅僅是在<bean>的autowire屬性里指定自動裝配的模式。
- byType(根據類型自動裝配):若IOC容器中有多個與目標Bean類型一致的Bean。在這種情況下,Spring將無法判定哪個Bean最適合該屬性,索引不能執行自動裝配。
- byName(根據名稱自動裝配):必須將目標Bean的名稱和屬性名設置的完全相同。
- constructor(通過構造器自動裝配):當Bean中存在多個構造器時,此種自動裝配方式將會很復雜,不推薦使用。
缺點
- 在Bean配置文件里設置autowire屬性進行自動裝配將會裝配Bean的所有屬性,然后,若只希望裝配個別屬性時,autowire屬性就不夠靈活了。
- autowire屬性要么根據類型自動裝配,那么根據名稱自動裝配,不能兩者兼而有之。
- 一般情況下,在實際的項目之中很少使用自動裝配功能,因為和自動裝配功能所帶來的好處比起來,明確清晰的配置文檔更好。
四.Bean之間的關系:繼承和依賴
1.繼承Bean配置
- Spring允許繼承Bean的配置,被繼承的Bean稱為父bean,繼承這個父bean的bean稱為子bean。
- 子Bean從父Bean中繼承配置,包括Bean的屬性配置。
- 子Bean也可以覆蓋從父Bean繼承過來的配置。
- 父Bean可以作為配置模板,也可以作為bean實例。若只想把父bean作為模板,可以設置<bean>的abstract屬性為true,這樣Spring將不會實例化這個Bean。
- 并不是<bean>元素里的所有屬性都會被繼承。比如autowire、abstract等。
- 也可以忽略父Bean的class屬性,讓子Bean指定自己的類,而共享相同的屬性配置,但此時abstract必須設為true。
2.依賴Bean配置
- Spring允許用戶通過depends-on屬性設定Bean前置依賴的Bean,前置依賴的Bean會在本Bean實例化之前創建好。
- 如果前置依賴于多個Bean,則可以通過逗號、空格的方式配置Bean的名稱。
五.bean的作用域
- 在Spring中,可以在<bean>元素的scope屬性里設置Bean的作用域。
- 默認情況下,Spring只為每個在IOC容器里面聲明的Bean創建唯一一個實例,整個IOC容器范圍內都能共享該實例:所有后續的getBean()調用和Bean引用都將返回這個唯一的Bean實例。該作用域被稱為singleton,它是所有bean的默認作用域。
類別 | 說明 |
---|---|
singleton | 在SpringIOC容器中僅存在一個Bean實例,Bean以單實例的方式存在 |
prototype | 每次調用getBean()時都會返回一個新的實例 |
request | 每次HTTP請求都會創建一個新的Bean,該作用域僅適用于WebApplicationContext環境 |
session | 同一個HTTP session共享一個Bean,不同的HTTP Session使用不同的Bean。該作用域僅適用于WebApplicationContext環境。 |
globalSession | 一般用于protlet應用環境,該作用域僅適用于WebApplicationContext環境。 |
六.使用外部屬性文件
1.在配置文件里配置Bean時,有時需要在Bean的配置里混入系統部署的細節信息(例如:文件路徑,數據源配置信息等)。而這些部署細節實際上需要和Bean配置相分離。
2.Spring提供了一個PropertyPlaceholderConfigurer的BeanFactory后置處理器,這個處理器允許用戶將Bean配置的部分內容外移到屬性文件中。可以在Bean配置文件里使用形式為 ${var} 的變量,PropertyPlaceholderConfigurer從屬性文件里加載屬性,并使用這些屬性來替換變量。
3.Spring還允許在屬性文件中使用${propName},以實現屬性直接的相互作用。
4.注冊PropertyPlaceholderConfigurer
Spring2.0的配置方式:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"></property>
</bean>
Spring2.5之后:可通過<context:property-placeholder>元素簡化:
- <beans>中添加context Schema定義
- 在配置文件中加入如下配置
<context:property-placeholder location="classpath:db.properties" />
七.SpEL
1.Spring表達式語言(簡稱SpELl):是一個支持運行時查詢和操作對象圖的強大的表達式語言。
- 語法類似于EL:SpELl使用#{...}作為界定符,所有再打括號中的字符都被認為是SpEL
- SpEL為bean的屬性進行動態賦值提供了便利。
- 通過SpELl可以實現:
- 通過bean的id對bean進行引用。
- 通過方法以及引用對象的中的屬性
- 計算表達式的值
- 正則表達式的匹配
2.SpEL的字面量
- 字面量的表示
- 整數:<property name="count" value="#{5}"/>
- 小數:<property name="count" value="#{87.9}"/>
- 科學計數法:<property name="count" value="#{1e4}"/>
- String可以使用單引號或者雙引號作為字符串的界定符號:<property name="count" value="#{'chuck'}"/>.
- booean: <property name="count" value="#{false}"/>
3.引用Bean、屬性和方法
- 應用其他對象
通過value屬性和SpELl配置bean之間的關系
<property name="prefix" value="#{prefixGenerator}"/>
- 引用其他對象的屬性
通過value屬性和SpELl配置suffix屬性值為另一個Bean的suffix屬性值
<property name="suffix" value="#{sequenceGenerator2.suffix}"/>
- 調用其他方法,還可以鏈式操作
通過value屬性和SpELl配置suffix屬性值為另一個Bean的方法的返回值
<property name="suffix" value="#{sequenceGenerator2.toString()}"/>
方法的鏈式操作
<property name="count" value="#{sequenceGenerator2.toString().toUpperCase()}"/>
-調用靜態方法或靜態屬性:通過T()調用一個類的靜態方法,它將返回一個Class Object,然后再調用相應的方法或屬性。
<property name="initValue" value="#{T(java.lang.Math).PI}"></property>
4. SpEL支持的運算符號
- 數學運算符:+,-,*,/,%,^:
- 加好還可以用作字符串的連接。
- 比較運算符:<,>,==,<=,>=,lt,gt,eq,le,ge
- 邏輯運算符:and,or,not,|
- if-else運算符:?:(ternary),?:(Elvis)
- if-else的變體
- 正則表達式:matches
八.Bean的生命周期
1.IOC容器中Bean的生命周期方法
- Spring IOC容器可以管理Bean的生命周期,Spring允許在Bean生命周期的特定點執行定制的任務。
- SpringIOC容器對Bean的生命周期進行管理的過程:
- 通過構造器或工廠方法創建Bean實例。
- 為Bean的屬性設置值和對其他Bean的引用。
- 調用Bean的初始化方法。
- Bean可以使用了。
- 當容器關閉了,調用Bean的銷毀方法。
- 在Bean的聲明里設置init-method和destroy-method屬性,為Bean指定初始化和銷毀方法。
2.創建Bean后置處理器
- Bean后置處理器允許在調用初始化方法前后對Bean進行額外的處理。
- Bean后置處理器對IOC容器里的所有Bean實例逐一處理,而非單一實例。其典型應用是:檢查Bean屬性的正確性或根據特定的標準更改Bean的屬性。
- 對Bean后置處理器而言,需要實現BeanPostProcessor接口。在初始化方法被調用前后,Spring將把每個Bean實例分別傳遞給上述接口的postProcessAfterInitialization()方法和postProcessBeforeInitialization()方法。
3.添加后置處理器后Bean的生命周期
SpringIOC容器對Bean的生命周期進行管理的過程:
- 通過構造器或工廠方法創建Bean實例。
- 為Bean的屬性設置值和對其他Bean的引用。
- 將Bean實例傳遞給Bean后置處理器的postProcessBeforeInitialization()方法。
- 調用Bean的初始化方法。
- 將Bean的實例傳遞給Bean的后置處理器的postProcessAfterInitialization()方法。
- Bean可以正常使用了。
- 當容器關閉時,調用Bean的銷毀方法。
4.通過調用靜態工廠方法創建Bean
- 調用靜態工廠方法創建Bean是將對象創建的過程封裝到靜態方法中。當客戶端需要對象時,只需要簡單地調用靜態方法,而不用關心創建對象的細節。
- 要聲明通過靜態方法創建的Bean,需要在Bean的class屬性里面這么擁有該工廠的方法的類,同時在factory-method屬性里指定工廠方法的名稱。最后使用<constrctor-arg>元素為該方法傳遞方法參數。
5.通過調用實例工廠方法創建Bean
- 實例工廠方法:將對象的創建過程封裝到另外一個對象實例的方法里。當客戶端需要請求對象時,只需要簡單的調用該實例方法而不需要關系對象的創建細節。
- 要聲明通過實例工廠方法創建的Bean
- 在bean的factory-bane屬性里指定擁有該工廠方法的bean。
- 在factory-method屬性里指定該工廠方法的名稱。
- 使用constructor-arg元素為工廠方法傳遞方法參數。
6.實現FactoryBean接口在SpringIOC容器中配置Bean
- Spring中有兩種類型的Bean,一種是普通Bean,另一種是工廠Bean,即FactoryBean。
- 工廠Bean跟普通Bean不同,其返回的對象不是指定類的一個實例,其返回的是該工廠Bean的getObject方法所返回的對象。
九.組件裝配
1.在classpath中掃描組件
- 組件掃描:spring能夠從classpath下自動掃描,偵測和實例化具有特定注解的組件。
- 特定組件包括:
- @Component:基本注解,標識了一個受Spring管理的組件。
- @Responsitory:標識持久層組件。
- @Service:標識服務層(業務層)組件。
- @Controller:標識表現出組件。
- 對于掃描到的組件,Spring有默認的命名策略:使用非限定類名,第一個字母小寫。也可以在注解中通過value屬性值標識組件的名稱。
- 當在組件類上使用了特定的注解之后,還需要在Spring的配置文件聲明<context:component-scan>:
base-package屬性制定一個要掃描的基類包,Spring容器將會掃描這個基類包及其子包中的所有類。
當需要掃描多個包時,可以使用逗號隔開。
如果僅希望掃描特定的類而非基類包下的所有類,可使用resource-pattern屬性過濾特定的類。
<context:include-filter>子節點表示要包含的目標類。
<context:exclude-filter>子節點表示要排除在外的目標類。
<context:component-scan>下面可以擁有若干個<context:include-filter>和<context:exclude-filter>子節點。
<context:component-scan base-package="com.desperado.helloworld" resource-pattern="autowire/*.class />
- <context:include-filter>和<context:exclude-filter>子節點支持多種類型的過濾表達式。
類別 | 示例 | 說明 |
---|---|---|
annotation | com.desperado.XxxAnnotation | 所有標注了XXXAnnotation的類。該類型采用目標;類是否標注了某個注解進行過濾。 |
assinable | com.desperado.XxxService | s所有繼承或擴展XXXService的類。該類型采用目標類是否繼承或擴展某個特定類進行過濾。 |
aspectj | com.desperado..*Service+ | 所有類名以Service結尾的類以及繼承或擴展它們的類。該類型采用AspectJ表達式進行過濾 |
regex | com.desperado.anno..* | 所有com.desperado.anno包下面的類。該類型采用正則表達式根據類的類名進行過濾。 |
custom | com.desperado.XxxTypeFilter | 采用XXXTypeFilter通過代碼的方式定義過濾規則。該類必須實現org.springframework.core.type.TypeFilter接口 |
- <context:component-scan>元素還會自動注冊AutowiredAnnotationBeanPostProcessor實例,該實例可以自動裝配具有@Autowired和@Resource、@Inject注解的屬性。
2.使用@Autowired自動裝配Bean
@Autowired注解自動裝配具有兼容類型單個Bean屬性。
- 構造器,普通字段(即使是非public),一切具有參數的方法都可以應用@Autowired注解。
- 默認情況下,所有使用@Autowired注解的屬性都需要被設置。當Spring找不到匹配的Bean裝配屬性時,會拋出異常,若某一屬性允許不被設置,可以設置@Autowired注解的required屬性為false。
- 默認情況下,當IOC容器里存在多個類型兼容的Bean時,通過類型的自動裝配將無法工作,此時可以在@Qualifier注解里提供Bean的名稱。Spring允許對方法的入參標準@Qualifiter已指定Bean的名稱。
- @Autowired注解也可以應用在數組類型的屬性上,此時Spring將會把所有匹配的Bean進行自動裝配。
- @Autowired注解也可以應用在集合屬性上,此時Spring讀取該集合的類型信息,然后自動裝配所有與之兼容的Bean。
- @Autowired注解用在java.util.Map上時,若該Map的鍵值為String,那么Spring將自動裝配與之Map值類型兼容的Bean,此時Bean的名稱作為鍵值。
3.使用@Resource或@Inject自動裝配Bean
- Spring還指出@Resource和@Inject注解,這兩個注解和@Autowired注解的功用類似。
- @Resource注解要求提供一個Bean名稱的屬性,若該屬性為空,則自動采用標注處的變量或方法名作為Bean的名稱。
- @Inject和@Autowired注解一樣也是按類型匹配注入的Bean,但沒有required屬性。
- 建議使用@Autowired注解
十.泛型依賴注入
Spring4.x中可以為子類注入子類對應的泛型類型的常用變量的引用。
十一.整個多個配置文件
Spring允許通過<import>將多個配置文件引入到一個文件中,進行配置文件的集成。這樣在啟動Spring容器時,僅需要指定這個合并好的配置文件就可以。
import元素的resource屬性支持Spring的標準的路徑資源
地址前綴 | 示例 | 對應資源類型 |
---|---|---|
classpath: | classpath:spring-mvc.xml | 從類路徑下加載資源,classpath:和classpath:/是等價的 |
file: | file:/conf/security/spirng-shiro.xml | 從文件系統目錄中裝載資源,可采用絕對或相對路徑 |
http:// | http:///www.desperado.com/resource/beans.xml | 從web服務器中加載資源 |
ftp:// | ftp://www.desperado.com/resource/beans.xml | 從FTP服務器中加載資源。 |