Spring框架總結【無比詳細】
以下內容是我在初學spring時候做的筆記,當時是把比較放在了備忘錄裡面,如今把筆記重整到csdn上,為了複習也為了分析給大家,筆記寫的算比較完整,回看自己做的還是有點羞澀。如有錯誤之處,歡迎指正,當我日後更強大的時候,我會不斷的對內容進行補充和完善。當然學習也就是這麼一個過程,學習-實踐-總結-實踐-總結... 轉載請申明原文地址,希望大家支援,謝謝。
1、IOC和DI
IOC: 控制反轉
即控制權的轉移,將我們建立物件的方式反轉了,以前物件的建立是由我們開發人員自己維護,包括依賴關係也是自己注入。使用了spring之後,物件的建立以及依賴關係可以由spring完成建立以及注入,反轉控制就是反轉了物件的建立方式,從我們自己建立反轉給了程式建立(spring)
DI: Dependency Injection 依賴注入
spring這個容器中,替你管理著一系列的類,前提是你需要將這些類交給spring容器進行管理,然後在你需要的時候,不是自己去定義,而是直接向spring容器索取,當spring容器知道你的需求之後,就會去它所管理的元件中進行查詢,然後直接給你所需要的元件.
實現IOC思想需要DI做支援
注入方式: 1.set方式注入 2.構造方法注入 3.欄位注入
注入型別: 1.值型別注入 2.引用型別注入
好處:
1.降低元件之間的耦合度,實現軟體各層之間的解耦.
2.可以使容器提供眾多服務如事務管理訊息服務處理等等。當我們使用容器管理事務時,開發人員就不需要手工 控制事務,也不需要處理複雜的事務傳播
3.容器提供單例模式支援,開發人員不需要自己編寫實現程式碼.
4.容器提供了AOP技術,利用它很容易實現如許可權攔截,執行期監控等功能
5.容器提供眾多的輔佐類,使這些類可以加快應用的開發.如jdbcTemplate HibernateTemplate
2.applicationContext & BeanFactory區別
BeanFactory介面
(1) spring的原始介面,針對原始介面的實現類功能較為單一
(2)BeanFactory介面實現類的容器,特點是每次在獲得物件時才會建立物件
ApplicationContext介面
(1)每次容器啟動時就會建立容器中配置的所有物件
(2)提供了更多功能
(3)從類路徑下載入配置檔案: ClassPathXmlApplicationContext
從硬碟的絕對路徑下載入配置檔案:FileSystemXmlApplication
3.spring配置詳解
3.1、元素屬性
bean元素:使用該元素描述需要spring容器管理物件
name屬性:給被管理的物件起個名字,獲得物件時getBean("name值")
class屬性:被管理物件的完整類名
id屬性:與name屬性一模一樣,名稱不可重複,不能使用特殊字元
name和id之間的一些注意點:
1、配置兩個相同的 id 或者 name 都不能通過。
2、如果既配置了 id ,也配置了 name ,則兩個都生效。如果id和name都沒有指定,則用類全名作為name,如<bean class="com.stamen.BeanLifeCycleImpl">,則你可以通過getBean("com.stamen.BeanLifeCycleImpl")返回該例項。
3、如果配置基本類的時候,註解和配置檔案都使用的時候,註解和配置檔案中 name 相同的時候, 則兩個衝突,配置檔案生效。
如果配置基本類的時候,註解和配置檔案都使用的時候,註解和配置檔案中 name 不相同的時候, 則兩個不衝突,都能夠生效。
3.2、bean元素進階( scope屬性 生命週期屬性)—————單例多例
(1)scope屬性
(1)singleton 預設值
單例物件 :被標識為單例的物件在spring容器中只會存在一個例項
(2)prototype
多例原型:被標識為多例的物件,每次在獲得才會被建立,每次建立都是新的物件
(3)request
Web環境下,物件與request生命週期一致
(4)session
Web環境下,物件與session生命週期一致
總結:絕大多數情況下,使用單例singleton(預設值),但是在與struts整合時候,務必要用prototype多例,因為struts2在每次請求都會建立一個新的Action,若為單例,在多請求情況下,每個請求找找spring拿的都是同一個action。
(2)生命週期屬性(瞭解)———初始化和銷燬
(1)配置一個方法作為生命週期初始化方法,spring會在物件建立之後立刻呼叫 init-method
(2)配置一個方法作為生命週期的銷燬方法,spring容器在關閉並銷燬所有容器中的物件之前呼叫destory-method
<bean init-method=“init” destory-method=“destory”></bean> 對應註解為@PostConstruct
<bean name=“hello” class=“完整類名”></bean> 對應註解為@PreDestory
(3)模組化配置,即分模組配置(匯入其他spring配置檔案)
<beans>
<import resource = “spring配置檔案的全路徑名” />
</beans>
3.3、spring三種物件的建立方式
(1)空引數構造(重要)
(2)靜態工廠建立(呼叫靜態方法建立)
呼叫UserFactory類的靜態createUser方法建立名為user的物件,放入容器
<bean name="user" class="cn.itcats.UserFactory" factory-method="createUser"></bean>
(3)例項工廠建立(呼叫非靜態方法建立)——需要配置兩個bean,因為無法通過類名呼叫非靜態方法
<bean name="user2" factory-bean="userFactory" factory-method="createUser"></bean>
<bean name=“userFactory” class=“cn.itcats.UserFactory”></bean>
3.4、spring注入方式
(1)set方式注入(重點)————值型別用value注入 引用型別用ref注入
(2)構造方法注入
函式注入
(3)p名稱空間注入———實際上set注入,spring特有,為了簡化<property>寫法
1、applicationContext.xml中<beans>標籤頭部匯入p名稱空間
xmlns:p="http://www.springframework.org/schema/p"
2、書寫格式:值型別注入—— p:屬性名="值" 引用型別注入—— p:屬性名-ref="引用的<bean> name屬性"
把Run類中的name屬性值設定為haha,age屬性設定為20,引用屬性hello引用<bean name="hello" class="..."></bean>
<bean name="run2" class="cn.itcats.thread.Run" p:name="haha" p:age="20" p:hello-ref="hello"></bean>
(4)spel注入: spring Expression Language spring表示式語言
<bean name="runSpel" class="cn.itcats.thread.Run">
<!-- 取bean標籤中name為"user"中property為"name"中的value值 --!>
<property name="name" value="#{user.name}"></property>
</bean>
SpEL特性:(1)、使用Bean的ID來引用Bean;(2)、呼叫方法和訪問物件的屬性;(3)、對值進行算術、關係和邏輯運算;(4)、正則表示式匹配;(5)、集合操作
複雜型別注入
1.array陣列的注入
2.list集合的注入
3.map集合的注入
4.properties的注入
4、防止建立多個applicationContext取值/並指定記載spring配置檔案的位置——web.xml
1、需要匯入包spring-web
2、在web.xml中配置監聽器
5、使用註解方式代替配置檔案(官方推薦使用註解)
1.在applicationContext.xml中書寫指定掃描註解
2.在類中書寫Component
注意:假如不寫括號內的值(即name或id),預設使用類名首字母小寫作為搜尋,為什麼意思呢?
比如Student類中使用了@Component 沒有書寫括號和值,那麼預設搜尋id或name為student。
3.指定物件的作用範圍Scope
宣告Student類物件為多例 下面是對singleton和prototype的一些補充
singleton作用域:當把一個Bean定義設定為singleton作用域是,Spring IoC容器中只會存在一個共享的Bean例項,並且所有對Bean的請求,只要id與該Bean定義相匹配,則只會返回該Bean的同一例項。值得強調的是singleton作用域是Spring中的預設作用域。
prototype作用域:prototype作用域的Bean會導致在每次對該Bean請求(將其注入到另一個Bean中,或者以程式的方式呼叫容器的getBean()方法)時都會建立一個新的Bean例項。根據經驗,對有狀態的Bean應使用prototype作用域,而對無狀態的Bean則應該使用singleton作用域。對於具有prototype作用域的Bean,有一點很重要,即Spring不能對該Bean的整個生命週期負責。具有prototype作用域的Bean建立後交由呼叫者負責銷燬物件回收資源。簡單的說:
singleton 只有一個例項,也即是單例模式。
prototype訪問一次建立一個例項,相當於new。
4.值型別的注入
實際通過反射field賦值
實際通過set方式賦值
5.引用型別的注入
面試題: @AutoWired和@Resource的區別?
@AutoWired預設以型別進行查詢,@Resource預設以名稱進行查詢
@AutoWired(required=false) + @Qualifier("user") == @Resource(name="user")
其中@Resource註解是jdk1.6後才有的
6.建立與銷燬方法
7.spring整合junit測試(spring建立容器)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
6、spring中AOP名詞解釋
JoinPoint(連線點):目標物件中,所有可以增強的方法,就是spring允許你是通知(Advice)的地方,那可就真多了,基本每個方法的前、後(兩者都有也行),或丟擲異常是時都可以是連線點,spring只支援方法連線點。
Pointcut(切入點):目標物件中,已經被增強的方法。呼叫這幾個方法之前、之後或者丟擲異常時乾點什麼,那麼就用切入點來定義這幾個方法。
Advice(通知/增強) :增強方法的程式碼、想要的功能。
Target(目標物件):被代理物件,被通知的物件,被增強的類物件。
Weaving(織入):將通知應用到連線點形成切入點的過程
Proxy(代理):將通知織入到目標物件之後形成的代理物件
aspect(切面):切入點+通知————通知(Advice)說明了幹什麼的內容(即方法體程式碼)和什麼時候幹(什麼時候通過方法名中的before,after,around等就能知道),二切入點說明了在哪幹(指定到底是哪個方法),切點表示式等定義。
雖然現在都用Maven專案構建,但是不能忘記,使用aop需要用到的包:spring-aop + spring-aspects + springsource.org.aopalliance + springsource.org.aspectj.weaver
關於AOP看一個小例子:
1、準備目標物件(被代理物件,被通知的物件,被增強的類物件)
2、準備通知(被增強方法的程式碼,想要實現功能的方法程式碼)
3、配置 applicationContext.xml
1.匯入aop(約束)名稱空間
2.配置目標物件
3.配置通知物件
4.配置將通知織入目標物件
4、測試
總結:通知的幾種型別
1.前置通知———目標方法執行之前呼叫
2.後置通知———目標方法執行之後呼叫(如果出現異常不呼叫)
3.環繞通知———目標方法之前和之後都呼叫
4.異常攔截通知———如果出現異常,就會呼叫
5.後置通知———目標方法執行之後呼叫(無論是否出現異常都會呼叫)
7、spring中的aop使用註解配置
1、applicationContext.xml中配置目標物件,通知物件,開啟使用註解完成織入
2、@Aspect註解代表該類是個通知類,書寫切點表示式@Pointcut("execution(返回值 全類名.方法名(引數))")
注意環繞通知需要這麼寫:
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//環繞方法執行前
//proceedingJoinPoint.proceed();表示對攔截的方法進行放行
//若註釋proceedingJoinPoint.proceed()則不會執行被AOP匹配的方法
proceedingJoinPoint.proceed();
//環繞方法執行前
}
AOP註解解析:
@Before
前置通知(Before advice) :在某連線點(JoinPoint)——核心程式碼(類或者方法)之前執行的通知,但這個通知不能阻止連線點前的執行。為啥不能阻止執行緒進入核心程式碼呢?因為@Before註解的方法入參不能傳ProceedingJoinPoint,而只能傳入JoinPoint。要知道從aop走到核心程式碼就是通過呼叫ProceedingJionPoint的proceed()方法。而JoinPoint沒有這個方法。
這裡牽扯區別這兩個類:Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎上暴露出 proceed 這個方法。proceed很重要,這個是aop代理鏈執行的方法。暴露出這個方法,就能支援 aop:around 這種切面(而其他的幾種切面只需要用到JoinPoint,這跟切面型別有關), 能決定是否走代理鏈還是走自己攔截的其他邏輯。建議看一下 JdkDynamicAopProxy的invoke方法,瞭解一下代理鏈的執行原理。這樣你就能明白 proceed方法的重要性。
@After
後通知(After advice) :當某連線點退出的時候執行的通知(不論是正常返回還是異常退出)。
@AfterReturning
返回後通知(After return advice) :在某連線點正常完成後執行的通知,不包括丟擲異常的情況。
@Around
環繞通知(Around advice) :包圍一個連線點的通知,類似Web中Servlet規範中的Filter的doFilter方法。可以在方法的呼叫前後完成自定義的行為,也可以選擇不執行。這時aop的最重要的,最常用的註解。用這個註解的方法入參傳的是ProceedingJionPoint pjp,可以決定當前執行緒能否進入核心方法中——通過呼叫pjp.proceed();
@AfterThrowing
丟擲異常後通知(After throwing advice) : 在方法丟擲異常退出時執行的通知。
8、spring整合jdbc
spring中提供了一個可以操作資料庫的物件,物件封裝了jdbc技術 ————JDBCTemplate JDBC模板物件,而JdbcDaoSupport則對JdbcTemplate進行了封裝,所以要操作JdbcTemplate,或只需要繼承JdbcDaoSupport即可。
依賴關係配置:
測試:
9、spring中的aop事務
事務的四大基本特性:
事物的概述
⑴ 原子性(Atomicity)
原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,因此事務的操作如果成功就必須要完全應用到資料庫,如果操作失敗則不能對資料庫有任何影響。
⑵ 一致性(Consistency)
一致性是指事務必須使資料庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之後都必須處於一致性狀態。
拿轉賬來說,假設使用者A和使用者B兩者的錢加起來一共是5000,那麼不管A和B之間如何轉賬,轉幾次賬,事務結束後兩個使用者的錢相加起來應該還得是5000,這就是事務的一致性。
⑶ 隔離性(Isolation)
隔離性是當多個使用者併發訪問資料庫時,比如操作同一張表時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。
即要達到這麼一種效果:對於任意兩個併發的事務T1和T2,在事務T1看來,T2要麼在T1開始之前就已經結束,要麼在T1結束之後才開始,這樣每個事務都感覺不到有其他事務在併發地執行。
關於事務的隔離性資料庫提供了多種隔離級別,稍後會介紹到。
⑷ 永續性(Durability)
永續性是指一個事務一旦被提交了,那麼對資料庫中的資料的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丟失提交事務的操作。
例如我們在使用JDBC操作資料庫時,在提交事務方法後,提示使用者事務操作完成,當我們程式執行完成直到看到提示後,就可以認定事務以及正確提交,即使這時候資料庫出現了問題,也必須要將我們的事務完全執行完成,否則就會造成我們看到提示事務處理完畢,但是資料庫因為故障而沒有執行事務的重大錯誤。
spring中事務的分類:
spring中事務可以分為程式設計式事務控制和宣告式事務控制。
程式設計式事務控制
自己手動控制事務,就叫做程式設計式事務控制。
Jdbc程式碼:
Conn.setAutoCommit(false); // 設定手動控制事務
Hibernate程式碼:
Session.beginTransaction(); // 開啟一個事務
【細粒度的事務控制: 可以對指定的方法、指定的方法的某幾行新增事務控制】
(比較靈活,但開發起來比較繁瑣: 每次都要開啟、提交、回滾.)
宣告式事務控制
Spring提供了對事務的管理, 這個就叫宣告式事務管理。
Spring提供了對事務控制的實現。使用者如果想用Spring的宣告式事務管理,只需要在配置檔案中配置即可; 不想使用時直接移除配置。這個實現了對事務控制的最大程度的解耦。
Spring宣告式事務管理,核心實現就是基於Aop。
【粗粒度的事務控制: 只能給整個方法應用事務,不可以對方法的某幾行應用事務。】
(因為aop攔截的是方法。)
Spring宣告式事務管理器類:
Jdbc技術:DataSourceTransactionManager
Hibernate技術:HibernateTransactionManager
有一點需要注意的:若為程式設計式事務控制,則開啟事務後一定要手動釋放(提交或回滾),否則長期佔用記憶體,有可能報事務異常
spring封裝了事務管理的程式碼(開啟,提交,回滾事務)
事務操作物件,因為在不同平臺,操作事務的程式碼各不相同.spring提供了一個介面
————— PlatformTransactionManager 介面
————— 在不同平臺,實現不同的介面即可
————— 注意:在spring中玩事務管理.最為核心的物件就是TransactionManager物件
spring管理事務的屬性介紹
(1)事務的隔離級別
(2)是否只讀
(3)事務的傳播行為
配置事務的核心管理器,它封裝了所有事務,依賴於連線池(DataSourceTransactionManager)
xml中配置通知
配置將通知織入目標
10.spring中aop管理事務 註解使用步驟
在需要管理的方法或者類中宣告配置事務管理
@Transactional(isolation=Isolation.REPEATABLE_READ,readOnly=false,propagation=Propagation.REQUIRED)