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的名稱。