Java框架之Spring01-IOC-bean配置-檔案引入-註解裝配
Spring
框架,即framework。是對特定應用領域中的應用系統的部分設計和實現的整體結構。就相當於讓別人幫你完成一些基礎工作,它可以處理系統很多細節問題,而且框架一般是成熟,穩健的。
Spring概述
Spring是一個IOC(DI)和AOP容器框架
Spring的優良特性
① 非侵入式:基於Spring開發的應用中的物件可以不依賴於Spring的API
② 依賴注入:DI——Dependency Injection,反轉控制(IOC)最經典的實現。
③ 面向切面程式設計:Aspect Oriented Programming——AOP
④ 容器:Spring是一個容器,因為它包含並且管理應用物件的生命週期
⑤ 元件化:Spring實現了使用簡單的元件配置組合成一個複雜的應用。在 Spring 中可以使用XML和Java註解組合這些物件。
⑥ 一站式:在IOC和AOP的基礎上可以整合各種企業應用的開源框架和優秀的第三方類庫(實際上Spring 自身也提供了表述層的SpringMVC和持久層的Spring JDBC)。
Spring模組
IOC和DI
IOC(Inversion of Control):反轉控制
反轉了資源的獲取方向——改由容器主動的將資源推送給需要的元件,開發人員不需要知道容器是如何建立資源物件的,只需要提供接收資源的方式即可。這種行為也稱為查詢的被動形式。
DI(Dependency Injection):依賴注入
即元件以一些預先定義好的方式(例如:setter 方法)接受來自於容器的資源注入。
總結: IOC 就是一種反轉控制的思想, 而DI是對IOC的一種具體實現。
IOC容器在Spring中的實現
匯入Spring框架jar包
建立配置檔案,常用檔名:applicationContext.xml或beans.xml
- Spring中有IOC思想, IOC思想必須基於 IOC容器來完成, 而IOC容器在最底層實質上就是一個物件工廠
1)在通過IOC容器讀取Bean的例項之前,需要先將IOC容器本身例項化。
2)Spring提供了IOC容器的兩種實現方式
① BeanFactory:IOC容器的基本實現,是Spring內部的基礎設施,是面向Spring本身的,不是提供給開發人員使用的。
② ApplicationContext:BeanFactory的子介面,提供了更多高階特性。面向Spring的使用者,幾乎所有場合都使用ApplicationContext而不是底層的BeanFactory。
ApplicationContext的主要實現類
ClassPathXmlApplicationContext:對應類路徑下的XML格式的配置檔案
FileSystemXmlApplicationContext:對應檔案系統中的XML格式的配置檔案
在初始化時就建立單例的bean,也可以通過配置的方式指定建立的Bean是多例項的。
ConfigurableApplicationContext
是ApplicationContext的子介面,包含一些擴充套件方法
refresh()和close()讓ApplicationContext具有啟動、關閉和重新整理上下文的能力。所以要關閉ApplicationContext需要new此介面的物件呼叫close()方法
WebApplicationContext
專門為WEB應用而準備的,它允許從相對於WEB根目錄的路徑中完成初始化工作
從IOC容器中獲取bean,推薦同時指定bean的id值和型別
//通過在XML檔案中配置的id及class型別獲取物件 HelloWorld helloWorld = cxt.getBean("helloWorld",HelloWorld.class);
bean標籤
bean標籤:將bean裝配到springIOC容器中
bean標籤中屬性
id:物件唯一標識(可以不寫,如果書寫必須是唯一值)
class:裝配bean的全類名
bean子標籤
property:為物件中的屬性賦值
name:屬性名
value:屬性值
constructor-arg:通過構造器賦值
給bean的屬性賦值
1. 通過bean的setXxx()方法賦值
2. 通過bean的構造器賦值,注意:如果構造器中引數型別相容,可能出現錯誤賦值情況。
<bean id="student" class="com.bean.Student01"> <property name="name" value="小明"></property> <constructor-arg name="age" value="18"></constructor-arg> </bean>
3. p名稱空間
<bean id="student" class="com.bean.Student01" p:name="小明" p:age="18"> </bean>
屬性可使用的值
1. 字面量
基本資料型別及其封裝類、String等型別都可以採取字面值注入的方式
若字面值中包含特殊字元,可以使用<![CDATA[]]>把字面值包裹起來或轉義字元
2. null值
<property name= "bookName"> <null/> </property>
3. 給bean的級聯屬性賦值
設定級聯屬性後會修改原屬性值,一般不使用
4. 外部已宣告的bean、引用其他的bean:此時value已經滿足不了需求了要用ref屬性
<bean id="school" class="com.bean.School"> <property name="stus" ref="stu"></property> </bean>
5. 內部bean
當bean例項僅僅給一個特定的屬性使用時,可以將其宣告為內部bean。內部bean宣告直接包含在<property>或<constructor-arg>元素裡,不需要設定任何id或name屬性
內部bean不能使用在任何其他地方,即不能在容器中直接獲取內部bean
為bean注入集合屬性
陣列和List:
需要指定<list>標籤,在標籤裡包含一些元素。這些標籤可以通過<value>指定簡單的常量值,通過<ref>指定對其他Bean的引用。通過<bean>指定內建bean。通過<null/>指定空元素。甚至可以內嵌其他集合。
陣列的定義和List一樣,都使用<list>元素。
配置java.util.Set需要使用<set>標籤,定義的方法與List一樣。
<bean id="shop" class="com.spring.bean.Shop" > <property name= "bookList"> <!-- 以bean的引用為值的List集合 --> <list> <ref bean= "book01"/> <ref bean= "book02"/> </list> </property> </bean >
Map
通過<map>標籤定義,<map>標籤裡可以使用多個<entry>作為子標籤。每個條目包含一個鍵和一個值。
必須在<key>標籤裡定義鍵,因為鍵和值的型別沒有限制,所以可以自由地為它們指定<value>、<ref>、<bean>或<null/>元素。
<bean id="cup" class="com.spring.bean.Cup"> <property name="bookMap"> <map> <entry key="book" value-ref="bookMap"></entry> <entry> <key> <value>bookKey01</value> </key> <ref bean="book01"/> </entry> </map> </property> </bean>
集合型別的bean
將集合bean的配置提取到外面,可供其他bean引用,實現重用
<util:list id="schoolList"> <ref bean="stu"></ref> </util:list>
FactoryBean
如果需要程式設計師參與建立bean的過程之中,使用FactoryBean
工廠bean跟普通bean不同,其返回的物件不是指定類的一個例項,其返回的是該工廠bean的getObject方法所返回的物件。
工廠bean必須實現org.springframework.beans.factory.FactoryBean介面,並重寫3個方法
<bean id="schoolFactory" class="com.factoryBeanImpl.SchoolFactory"> </bean>
bean的作用域
可以在<bean>元素的scope屬性裡設定bean的作用域,以決定這個bean是單例項的還是多例項的。
singleton,是所有bean的預設作用域。注意:工廠bean是通過isSingleton()方法設定是否單例的
當bean的作用域為單例時,Spring會在IOC容器物件建立時就建立bean的物件例項
而當bean的作用域為prototype時,IOC容器在獲取bean的例項時建立bean的例項物件
bean的生命週期
在配置bean時,通過init-method和destroy-method 屬性為bean指定初始化和銷燬方法
Spring IOC容器對bean的生命週期進行管理的過程:
① 通過構造器或工廠方法建立bean例項
② 為bean的屬性設定值和對其他bean的引用
③ 呼叫bean的初始化方法
④ bean可以使用了
⑤ 當容器關閉時,呼叫bean的銷燬方法
<bean id="stu" class="com.bean.Student" init-method="init" destroy-method="destroy"> </bean>
bean的後置處理器
① bean後置處理器允許在呼叫初始化方法前後對bean進行額外的處理
② bean後置處理器對IOC容器裡的所有bean例項逐一處理,而非單一例項。
③ bean後置處理器需要實現介面:org.springframework.beans.factory.config.BeanPostProcessor。
在初始化方法被呼叫前後,Spring將把每個bean例項分別傳遞給上述介面的以下兩個方法:
●postProcessBeforeInitialization(Object bean, String beanId):初始化之前執行
●postProcessAfterInitialization(Object, String):初始化之後執行
注意
引數bean:IOC容器中建立的物件
引數beanId:IOC容器中建立物件的beanId
引用外部檔案
將一部分資訊提取到bean配置檔案的外部,以properties格式的屬性檔案儲存起來,同時在bean的配置檔案中引用properties屬性檔案中的內容,從而實現一部分屬性值在發生變化時僅修改properties屬性檔案即可。
1. 建立properties屬性檔案
jdbc.username=root jdbc.password=12345 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test
2. 引入context名稱空間
3.指定properties屬性檔案的位置
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
classpath: 引入當前專案中類路徑下的資原始檔
classpath*: 引入所專案中類路徑下的資原始檔
4.從properties屬性檔案中引入屬性值
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" p:username="${jdbc.username}" p:password="${jdbc.password}" p:driverClassName="${jdbc.driverClass}" p:url="${jdbc.url}"> </bean>
自動裝配
手動裝配:在XML配置檔案中以value或ref的方式明確指定屬性值都是手動裝配。
自動裝配:根據指定的裝配規則,不需要明確指定,Spring容器會自動將匹配的屬性值注入bean中。
注意:自動裝配屬性的資料型別,只能是[非字面量]值。[字面量]值不能自動裝配。即基本資料型別(包裝類)+String型別都不可自動裝配
裝配方式
- 根據型別自動裝配:將型別匹配的bean作為屬性注入到另一個bean中。當有多個與目標bean型別一致將報錯
- 根據名稱自動裝配:必須將目標bean的名稱和屬性名設定的完全相同
- 通過構造器自動裝配:當bean中存在多個構造器時,此種自動裝配方式將會很複雜。不推薦使用。
基於xml,自動裝配(不推薦)
在bean中新增autowire="byName|byType"
<bean id="student" class="com.springdemo.autowired.Student" autowire="byType"></bean>
byName:通過類中的屬性名與bean中id(IOC容器中的id匹配)。
* 如果數值一致,匹配成功。 如果不一致,裝配失敗(不會報錯,裝配null值)
byType:通過類中的屬性型別與bean中的class匹配
* 如果一致,匹配成功。
* 如果未找到匹配型別,裝配失敗(裝配null值)
* 如果匹配到多個相容型別(父子關係:裝配失敗,結果會報錯)
基於註解,自動裝配bean
需在XML文件中先新增掃描元件標籤,指定需被裝配bean的package
<context:component-scan base-package="com.bookStore" use-default-filters="true"></context:component-scan>
base-package:Spring容器會掃描這個基類包及其子包中的所有類。當需要掃描多個包時可以使用逗號分隔。
如果僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類
use-default-filters="true":預設元件掃描(掃描當前base-package下的包及其子包),false:不掃描...
通過子標籤控制包含與排除
<context:include-filter>包含掃描,掃描指定匹配規則下的包及其子包
注意:通過將use-default-filters屬性設定為false,禁用預設過濾器,然後掃描的就只是include-filter中的規則指定元件了
<context:exclude-filter>排除掃描,子節點表示要排除在外的目標類
注意:將use-default-filters屬性設定為true或預設
過濾表示式,指定型別
類別 |
示例 |
說明 |
annotation |
com.XxxAnnotation |
過濾所有標註了XxxAnnotation的類。這個規則根據目標元件是否標註了指定型別的註解進行過濾。 |
assignable |
com.BaseXxx |
過濾所有BaseXxx類的子類。這個規則根據目標元件是否是指定型別的子類的方式進行過濾。 |
aspectj |
com.*Service+ |
所有類名是以Service結束的,或這樣的類的子類。這個規則根據AspectJ表示式進行過濾。 |
regex |
com\.anno\.* |
所有com.anno包下的類。這個規則根據正則表示式匹配到的類名進行過濾。 |
custom |
com.XxxTypeFilter |
使用XxxTypeFilter類通過編碼的方式自定義過濾規則。該類必須實現org.springframework.core.type.filter.TypeFilter介面 |
4個註解:
1) 普通元件:@Component
2) 表述層控制器元件:@Controller
3) 業務邏輯層元件:@Service
4) 持久化層元件:@Repository
元件命名規則
①預設情況:使用元件的簡單類名首字母小寫作為bean的id
②使用元件註解的value屬性指定bean的id: @Component(value="指定id名")
自動裝配bean中的屬性
實現原理
在指定要掃描的包時,<context:component-scan> 元素會自動註冊一個bean的後置處 理器:AutowiredAnnotationBeanPostProcessor的例項。該後置處理器可以自動裝配標記 了@Autowired、@Resource或@Inject註解的屬性。
@Autowired
注入方式:既不是set注入,也不是構造注入。本質:是通過反射注入。
自動裝配規則
優先使用byType進行裝配,如果能唯一匹配,則裝配成功。
如果匹配到多個相容型別的bean,再照byName方式匹配(進行唯一篩選)
如果通過byName唯一確定bean,則裝配成功,否則裝配失敗。
構造器、普通欄位(即使是非public)、一切具有引數的方法都可以使用@Autowired註解
若某一屬性允許不被裝配,可以設定@Autowired註解的required屬性為 false
required:預設值是true,必須裝配該bean
required值為false時,如果IOC容器中存在該bean,則裝配。如果沒有,則不裝配。
@Autowired註解也可以應用在陣列型別的屬性上
@Autowired註解也可以應用在集合屬性上,此時Spring讀取該集合的型別資訊,然後自動裝配所有與之相容的bean。
@Autowired註解用在java.util.Map上時,若該Map的鍵值為String,那麼 Spring將自動裝配與值型別相容的bean作為值,並以bean的id值作為鍵。
@Qualifier
必要時,可以組合使用@Qualifier(value="userDaoMyBatisImpl")註解指定beanId名
Spring甚至允許在方法形參上標註@Qualifiter註解以指定注入bean的名稱