有時為了保證一些操作要麼都成功,要麼都失敗,這就需要事務來保證。
傳統的jdbc事務如下:
<a href="http://my.oschina.net/pingpangkuangmo/blog/376331#">?</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<code>@test</code>
<code> </code><code>public</code> <code>void</code> <code>testadd(){</code>
<code> </code><code>connection con=</code><code>null</code><code>;</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>con=drivermanager.getconnection(url , username , password )</code>
<code> </code><code>con.setautocommit(</code><code>false</code><code>);</code>
<code> </code><code>//操作一</code>
<code> </code><code>preparedstatement ps = con.preparestatement(</code><code>"insert into product(product_name,model) value('電腦','聯想')"</code><code>);</code>
<code> </code><code>ps.execute();</code>
<code> </code><code>//操作二</code>
<code> </code><code>ps = con.preparestatement(</code><code>"insert into product(product_name,model) value('電腦','聯想')"</code><code>);</code>
<code> </code>
<code> </code><code>con.commit();</code>
<code> </code><code>}</code><code>catch</code> <code>(sqlexception e) {</code>
<code> </code><code>e.printstacktrace();</code>
<code> </code><code>if</code><code>(con!=</code><code>null</code><code>){</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>con.rollback();</code>
<code> </code><code>}</code><code>catch</code> <code>(sqlexception e1) {</code>
<code> </code><code>e1.printstacktrace();</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
設定connection連接配接的自動送出為false,變成我們手動來控制commit時機。一旦操作一執行成功但是操作二執行失敗,在捕獲的異常中進行復原操作(其實也可以不用手動復原,當你沒有手動執行con.commit()方法時,也會復原)。
這種傳統的使用事務的方法有很多的弊端。
弊端一:業務代碼都要嵌套在try catch模闆代碼中
弊端二:接觸了底層connection的事務功能,當使用其他一些架構時,我們更多的不會直接與connection打交道,如使用hibernate時,就不容易擷取connection。
有了以上的兩點缺陷,我們就要分别來解決他們。
首先針對弊端一:
(1)既然外層代碼都是相似的try catch代碼,我們最能想到的就是将這些代碼封裝成模闆以便複用。如同jdbctemplate對jdbc操作的模闆代碼的封裝,這便引出了下文transactiontemplate的模闆代碼。
(2)當然了,上述做法還不是很理想,如何才能将我們的業務邏輯和事務代碼完全分離呢?這就需要使用aop代理技術。我們隻需要關系業務邏輯,通過aop代理将事務邏輯植入業務邏輯中,這樣就可以做到分離。這就需要将事務和aop很好的結合起來。
然後針對弊端二:
既然不推薦和底層connection打交道,那就需要一個統一的接口來完成事務的送出和復原等功能,即接口platformtransactionmanager,如果是使用jdbc則使用datasourcetransactionmanager來完成事務的送出和復原,若果是使用hibernate則使用hibernatetransactionmanager來完成事務的送出和復原。
下面就來仔細看下源代碼:
事務的定義接口為transactiondefinition,類圖如下:
先看transactiondefinition:
<code>public</code> <code>interface</code> <code>transactiondefinition {</code>
<code> </code><code>int</code> <code>propagation_required =</code><code>0</code><code>;</code>
<code> </code><code>int</code> <code>propagation_supports =</code><code>1</code><code>;</code>
<code> </code><code>int</code> <code>propagation_mandatory =</code><code>2</code><code>;</code>
<code> </code><code>int</code> <code>propagation_requires_new =</code><code>3</code><code>;</code>
<code> </code><code>int</code> <code>propagation_not_supported =</code><code>4</code><code>;</code>
<code> </code><code>int</code> <code>propagation_never =</code><code>5</code><code>;</code>
<code> </code><code>int</code> <code>propagation_nested =</code><code>6</code><code>;</code>
<code> </code><code>int</code> <code>isolation_default = -</code><code>1</code><code>;</code>
<code> </code><code>int</code> <code>isolation_read_uncommitted = connection.transaction_read_uncommitted;</code>
<code> </code><code>int</code> <code>isolation_read_committed = connection.transaction_read_committed;</code>
<code> </code><code>int</code> <code>isolation_repeatable_read = connection.transaction_repeatable_read;</code>
<code> </code><code>int</code> <code>isolation_serializable = connection.transaction_serializable;</code>
<code> </code><code>int</code> <code>timeout_default = -</code><code>1</code><code>;</code>
<code> </code><code>int</code> <code>getpropagationbehavior();</code>
<code> </code><code>int</code> <code>getisolationlevel();</code>
<code> </code><code>int</code> <code>gettimeout();</code>
<code> </code><code>boolean</code> <code>isreadonly();</code>
<code> </code><code>string getname();</code>
<code>}</code>
transactiondefinition接口:事務的定義,兩個重要屬性,事務的傳播屬性和隔離級别,這裡不再重點說明,可網上去查。
defaulttransactiondefinition:就是對上述屬性設定一些預設值,傳播屬性預設為:propagation_required,隔離級别預設為:isolation_default,采用的是底層資料庫采用的預設隔離級别。
transactionattribute接口:
<code>public</code> <code>interface</code> <code>transactionattribute</code><code>extends</code> <code>transactiondefinition {</code>
<code> </code><code>//在選擇事務管理器時用到</code>
<code> </code><code>string getqualifier();</code>
<code> </code><code>//指明對什麼樣的異常進行復原</code>
<code> </code><code>boolean</code> <code>rollbackon(throwable ex);</code>
defaulttransactionattribute:
<code>//對runtimeexception 和error都進行復原</code>
<code>public</code> <code>boolean</code> <code>rollbackon(throwable ex) {</code>
<code> </code><code>return</code> <code>(ex</code><code>instanceof</code> <code>runtimeexception || ex</code><code>instanceof</code> <code>error);</code>
以上的事務定義基本就沒什麼了。下面來看看上文針對弊端一采用的transactiontemplate:
26
27
28
29
30
31
32
33
34
<code>public</code> <code>class</code> <code>transactiontemplate</code><code>extends</code> <code>defaulttransactiondefinition</code>
<code> </code><code>implements</code> <code>transactionoperations, initializingbean {</code>
<code> </code><code>private</code> <code>platformtransactionmanager transactionmanager;</code>
<code>public</code> <code><t> t execute(transactioncallback<t> action)</code><code>throws</code> <code>transactionexception {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.transactionmanager</code><code>instanceof</code> <code>callbackpreferringplatformtransactionmanager) {</code>
<code> </code><code>return</code> <code>((callbackpreferringplatformtransactionmanager)</code><code>this</code><code>.transactionmanager).execute(</code><code>this</code><code>, action);</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>transactionstatus status =</code><code>this</code><code>.transactionmanager.gettransaction(</code><code>this</code><code>);</code>
<code> </code><code>t result;</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>result = action.dointransaction(status);</code>
<code> </code><code>catch</code> <code>(runtimeexception ex) {</code>
<code> </code><code>// transactional code threw application exception -> rollback</code>
<code> </code><code>rollbackonexception(status, ex);</code>
<code> </code><code>throw</code> <code>ex;</code>
<code> </code><code>catch</code> <code>(error err) {</code>
<code> </code><code>// transactional code threw error -> rollback</code>
<code> </code><code>rollbackonexception(status, err);</code>
<code> </code><code>throw</code> <code>err;</code>
<code> </code><code>catch</code> <code>(exception ex) {</code>
<code> </code><code>// transactional code threw unexpected exception -> rollback</code>
<code> </code><code>throw</code> <code>new</code> <code>undeclaredthrowableexception(ex,</code><code>"transactioncallback threw undeclared checked exception"</code><code>);</code>
<code> </code><code>this</code><code>.transactionmanager.commit(status);</code>
<code> </code><code>return</code> <code>result;</code>
它内部含有一個重要的屬性事務管理器platformtransactionmanager,用它來執行事務的送出和復原操作。
這樣的模闆代碼,使得我們隻需将我們的業務邏輯寫到transactioncallback接口方法中即可,案例如下:
<code>transactiontemplate transactiontemplate=</code><code>new</code> <code>transactiontemplate();</code>
<code>transactiontemplate.settransactionmanager(platformtransactionmanager);</code>
<code> </code>
<code> </code><code>transactiontemplate.execute(</code><code>new</code> <code>transactioncallback<string>() {</code>
<code> </code><code>@override</code>
<code> </code><code>public</code> <code>string dointransaction(transactionstatus status) {</code>
<code> </code><code>//資料庫操作1</code>
<code> </code><code>//資料庫操作2</code>
<code> </code><code>return</code> <code>"success"</code><code>;</code>
<code> </code><code>});</code>
這便是模闆代碼transactiontemplate,雖然幫我們省略了一些相同的操作,但是每次資料庫操作都要寫到transactioncallback中,與業務邏輯還不是分離的。這就引出aop代理。
要将springaop和事務結合起來,也有很多的表現形式,但原理都是一樣的。
如下形式:
形式1:
<code><</code><code>bean</code> <code>id</code><code>=</code><code>"proxy"</code>
<code> </code><code>class</code><code>=</code><code>"org.springframework.transaction.interceptor.transactionproxyfactorybean"</code><code>></code>
<code> </code><code><!-- 為事務代理工廠bean注入事務管理器 --></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"transactionmanager"</code> <code>ref</code><code>=</code><code>"transactionmanager"</code> <code>/></code>
<code> </code><code><!-- 要在哪個bean上面建立事務代理對象 --></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"target"</code> <code>ref</code><code>=</code><code>"productdao"</code> <code>/></code>
<code> </code><code><!-- 指定事務屬性 --></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"transactionattributes"</code><code>></code>
<code> </code><code><</code><code>props</code><code>></code>
<code> </code><code><</code><code>prop</code> <code>key</code><code>=</code><code>"*"</code><code>>propagation_required</</code><code>prop</code><code>></code>
<code> </code><code></</code><code>props</code><code>></code>
<code> </code><code></</code><code>property</code><code>></code>
<code></</code><code>bean</code><code>></code>
這種方式就是直接針對某個對象建立代理對象,加入事務攔截器。
形式2:
<code><</code><code>tx:advice</code> <code>id</code><code>=</code><code>"txadvice"</code> <code>transaction-manager</code><code>=</code><code>"transactionmanager"</code><code>> </code>
<code> </code><code><</code><code>tx:attributes</code><code>> </code>
<code> </code><code><</code><code>tx:method</code> <code>name</code><code>=</code><code>"add*"</code> <code>propagation</code><code>=</code><code>"required"</code> <code>/> </code>
<code> </code><code><</code><code>tx:method</code> <code>name</code><code>=</code><code>"delete*"</code> <code>propagation</code><code>=</code><code>"required"</code> <code>/> </code>
<code> </code><code><</code><code>tx:method</code> <code>name</code><code>=</code><code>"update*"</code> <code>propagation</code><code>=</code><code>"required"</code> <code>/> </code>
<code> </code><code><</code><code>tx:method</code> <code>name</code><code>=</code><code>"add*"</code> <code>propagation</code><code>=</code><code>"required"</code> <code>/> </code>
<code> </code><code></</code><code>tx:attributes</code><code>> </code>
<code> </code><code></</code><code>tx:advice</code><code>> </code>
<code> </code>
<code> </code><code><</code><code>aop:config</code><code>> </code>
<code> </code><code><</code><code>aop:pointcut</code> <code>id</code><code>=</code><code>"pointcut"</code>
<code> </code><code>expression</code><code>=</code><code>"xxxx"</code> <code>/> </code>
<code> </code><code><</code><code>aop:advisor</code> <code>advice-ref</code><code>=</code><code>"txadvice"</code>
<code> </code><code>pointcut-ref</code><code>=</code><code>"pointcut"</code> <code>/> </code>
<code> </code><code></</code><code>aop:config</code><code>></code>
這裡就比較明顯,tx:advice定義advice,對不同的方法名稱,定義不同的事務屬性,aop:config将上述通知和pointcut結合起來變成通知器。
這種方式将符合pointcut的對象都建立出代理對象,加入事務攔截器
形式3:
<code><</code><code>tx:annotation-driven</code> <code>transaction-manager</code><code>=</code><code>"transactionmanager"</code> <code>/></code>
這種形式結合@transactional來使用。
這種方式将标注有@transactional的對象來建立出代理對象。
以上三種形式都是将某些對象建立出代理對象(建立代理對象的方式不同),并加入事務攔截器。我們先來看看這個事務攔截器是什麼樣的。
先來看下transactioninterceptor:它繼承了transactionaspectsupport,實作了methodinterceptor接口。執行aop代理過程中,可以對目标業務邏輯加上各種各樣的攔截器,每一個攔截器都是一個methodinterceptor,每個methodinterceptor都有接口方法public object invoke(final methodinvocation invocation),methodinvocation更像是針對所攔截的方法的一個攔截器鍊條,通過它能夠不斷的執行該鍊條上的每個攔截器。
看下transactioninterceptor:
<code>public</code> <code>class</code> <code>transactioninterceptor</code><code>extends</code> <code>transactionaspectsupport</code><code>implements</code> <code>methodinterceptor, serializable {</code>
<code> </code><code>public</code> <code>transactioninterceptor() {</code>
<code> </code><code>public</code> <code>transactioninterceptor(platformtransactionmanager ptm, properties attributes) {</code>
<code> </code><code>settransactionmanager(ptm);</code>
<code> </code><code>settransactionattributes(attributes);</code>
<code> </code><code>public</code> <code>transactioninterceptor(platformtransactionmanager ptm, transactionattributesource tas) {</code>
<code> </code><code>settransactionattributesource(tas);</code>
<code> </code><code>@override</code>
<code> </code><code>public</code> <code>object invoke(</code><code>final</code> <code>methodinvocation invocation)</code><code>throws</code> <code>throwable {</code>
<code> </code><code>class<?> targetclass = (invocation.getthis() !=</code><code>null</code> <code>? aoputils.gettargetclass(invocation.getthis()) :</code><code>null</code><code>);</code>
<code> </code><code>return</code> <code>invokewithintransaction(invocation.getmethod(), targetclass,</code><code>new</code> <code>invocationcallback() {</code>
<code> </code><code>public</code> <code>object proceedwithinvocation()</code><code>throws</code> <code>throwable {</code>
<code> </code><code>return</code> <code>invocation.proceed();</code>
<code>//略</code>
前面幾個構造函數可以看到,transactioninterceptor 基本不保留任何資料,隻是起到資料傳遞作用,把真正的處理過程交給transactionaspectsupport 去完成,而本身則淨身更像一個攔截器,是以我們要去看transactionaspectsupport,在看它的攔截邏輯之前,先介紹下一個重要接口transactionattributesource:
<code>public</code> <code>interface</code> <code>transactionattributesource {</code>
<code> </code><code>transactionattribute gettransactionattribute(method method, class<?> targetclass);</code>
接口方法主要是擷取目标類的method方法的事務屬性。
這樣的擷取方式有很多
(1)使用注解來标注事務屬性,如@transactional注解
(2)使用配置資訊,如下
<code><tx:attributes> </code>
<code> </code><code><tx:method name=</code><code>"add*"</code> <code>propagation=</code><code>"required"</code> <code>/> </code>
<code> </code><code><tx:method name=</code><code>"delete*"</code> <code>propagation=</code><code>"required"</code> <code>/> </code>
<code> </code><code><tx:method name=</code><code>"update*"</code> <code>propagation=</code><code>"required"</code> <code>/> </code>
<code> </code><code><tx:method name=</code><code>"add*"</code> <code>propagation=</code><code>"required"</code> <code>/> </code>
<code> </code><code></tx:attributes></code>
直接xml配置某些方法的事務屬性。
類圖如下:
然後回到攔截器核心邏輯中:
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<code>protected</code> <code>object invokewithintransaction(method method, class<?> targetclass,</code><code>final</code> <code>invocationcallback invocation)</code>
<code> </code><code>throws</code> <code>throwable {</code>
<code> </code><code>// if the transaction attribute is null, the method is non-transactional.</code>
<code> </code><code>final</code> <code>transactionattribute txattr = gettransactionattributesource().gettransactionattribute(method, targetclass);</code>
<code> </code><code>final</code> <code>platformtransactionmanager tm = determinetransactionmanager(txattr);</code>
<code> </code><code>final</code> <code>string joinpointidentification = methodidentification(method, targetclass);</code>
<code> </code><code>if</code> <code>(txattr ==</code><code>null</code> <code>|| !(tm</code><code>instanceof</code> <code>callbackpreferringplatformtransactionmanager)) {</code>
<code> </code><code>// standard transaction demarcation with gettransaction and commit/rollback calls.</code>
<code> </code><code>transactioninfo txinfo = createtransactionifnecessary(tm, txattr, joinpointidentification);</code>
<code> </code><code>object retval =</code><code>null</code><code>;</code>
<code> </code><code>// this is an around advice: invoke the next interceptor in the chain.</code>
<code> </code><code>// this will normally result in a target object being invoked.</code>
<code> </code><code>retval = invocation.proceedwithinvocation();</code>
<code> </code><code>catch</code> <code>(throwable ex) {</code>
<code> </code><code>// target invocation exception</code>
<code> </code><code>completetransactionafterthrowing(txinfo, ex);</code>
<code> </code><code>finally</code> <code>{</code>
<code> </code><code>cleanuptransactioninfo(txinfo);</code>
<code> </code><code>committransactionafterreturning(txinfo);</code>
<code> </code><code>return</code> <code>retval;</code>
<code> </code><code>// it's a callbackpreferringplatformtransactionmanager: pass a transactioncallback in.</code>
<code> </code><code>object result = ((callbackpreferringplatformtransactionmanager) tm).execute(txattr,</code>
<code> </code><code>new</code> <code>transactioncallback<object>() {</code>
<code> </code><code>@override</code>
<code> </code><code>public</code> <code>object dointransaction(transactionstatus status) {</code>
<code> </code><code>transactioninfo txinfo = preparetransactioninfo(tm, txattr, joinpointidentification, status);</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>return</code> <code>invocation.proceedwithinvocation();</code>
<code> </code><code>}</code>
<code> </code><code>catch</code> <code>(throwable ex) {</code>
<code> </code><code>if</code> <code>(txattr.rollbackon(ex)) {</code>
<code> </code><code>// a runtimeexception: will lead to a rollback.</code>
<code> </code><code>if</code> <code>(ex</code><code>instanceof</code> <code>runtimeexception) {</code>
<code> </code><code>throw</code> <code>(runtimeexception) ex;</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>throw</code> <code>new</code> <code>throwableholderexception(ex);</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>// a normal return value: will lead to a commit.</code>
<code> </code><code>return</code> <code>new</code> <code>throwableholder(ex);</code>
<code> </code><code>finally</code> <code>{</code>
<code> </code><code>cleanuptransactioninfo(txinfo);</code>
<code> </code><code>}</code>
<code> </code><code>});</code>
<code> </code><code>// check result: it might indicate a throwable to rethrow.</code>
<code> </code><code>if</code> <code>(result</code><code>instanceof</code> <code>throwableholder) {</code>
<code> </code><code>throw</code> <code>((throwableholder) result).getthrowable();</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>return</code> <code>result;</code>
<code> </code><code>catch</code> <code>(throwableholderexception ex) {</code>
<code> </code><code>throw</code> <code>ex.getcause();</code>
第一步:使用transactionattributesource根據method和targetclass擷取事務屬性,上文已說過。
第二步:擷取合适的事務處理器
<code>protected</code> <code>platformtransactionmanager determinetransactionmanager(transactionattribute txattr) {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.transactionmanager !=</code><code>null</code> <code>||</code><code>this</code><code>.beanfactory ==</code><code>null</code> <code>|| txattr ==</code><code>null</code><code>) {</code>
<code> </code><code>return</code> <code>this</code><code>.transactionmanager;</code>
<code> </code><code>string qualifier = txattr.getqualifier();</code>
<code> </code><code>if</code> <code>(stringutils.haslength(qualifier)) {</code>
<code> </code><code>return</code> <code>beanfactoryannotationutils.qualifiedbeanoftype(</code><code>this</code><code>.beanfactory, platformtransactionmanager.</code><code>class</code><code>, qualifier);</code>
<code> </code><code>else</code> <code>if</code> <code>(</code><code>this</code><code>.transactionmanagerbeanname !=</code><code>null</code><code>) {</code>
<code> </code><code>return</code> <code>this</code><code>.beanfactory.getbean(</code><code>this</code><code>.transactionmanagerbeanname, platformtransactionmanager.</code><code>class</code><code>);</code>
<code> </code><code>return</code> <code>this</code><code>.beanfactory.getbean(platformtransactionmanager.</code><code>class</code><code>);</code>
首先如果該攔截器本身的事務攔截器不為空則直接使用,若為空則根據事務配置屬性中的qualifier屬性來比對,如果沒有再根據事務攔截器的transactionmanagerbeanname來比對,最後根據platformtransactionmanager類型來比對。
第三步:joinpointidentification則為類名和方法名的結合,主要用與log資訊。
第四步:根據事務管理器和事務屬性建立事務。
<code>transactioninfo txinfo = createtransactionifnecessary(tm, txattr, joinpointidentification);</code>
這樣的代碼仍然很清晰,先建立事務,執行業務邏輯,送出事務,當抛出異常時復原事務,這些操作都是由事務管理器platformtransactionmanager來完成的。本文不再詳細說明,下一篇文章重點來說事務管理器根據事務屬性對事務的送出復原等操作。
這裡再對上文的三種形式做源碼分析:
形式1:使用transactionproxyfactorybean工廠bean
内容不再列出,到上文找。transactionproxyfactorybean的類圖如下:
先從上面說起。
factorybean :工廠bean
<code>public</code> <code>interface</code> <code>factorybean<t> {</code>
<code> </code><code>t getobject()</code><code>throws</code> <code>exception;</code>
<code> </code><code>class<?> getobjecttype();</code>
<code> </code><code>boolean</code> <code>issingleton();</code>
一旦一個bean實作了factorybean 接口,注冊到spring容器中,根據注冊id擷取的對象不是此工廠bean而是該工廠bean的getobject()方法傳回的對象。
proxyconfig:代理配置
<code>public</code> <code>class</code> <code>proxyconfig</code><code>implements</code> <code>serializable {</code>
<code> </code><code>private</code> <code>boolean</code> <code>proxytargetclass =</code><code>false</code><code>;</code>
<code> </code><code>private</code> <code>boolean</code> <code>optimize =</code><code>false</code><code>;</code>
<code> </code><code>boolean</code> <code>opaque =</code><code>false</code><code>;</code>
<code> </code><code>boolean</code> <code>exposeproxy =</code><code>false</code><code>;</code>
<code> </code><code>private</code> <code>boolean</code> <code>frozen =</code><code>false</code><code>;</code>
abstractsingletonproxyfactorybean:建立單例的代理對象核心類,對子類隻留出攔截器。
<code>public</code> <code>abstract</code> <code>class</code> <code>abstractsingletonproxyfactorybean</code><code>extends</code> <code>proxyconfig</code>
<code> </code><code>implements</code> <code>factorybean<object>, beanclassloaderaware, initializingbean {</code>
<code> </code><code>private</code> <code>object target;</code>
<code> </code><code>private</code> <code>class<?>[] proxyinterfaces;</code>
<code> </code><code>private</code> <code>object[] preinterceptors;</code>
<code> </code><code>private</code> <code>object[] postinterceptors;</code>
<code> </code><code>/** default is global advisoradapterregistry */</code>
<code> </code><code>private</code> <code>advisoradapterregistry advisoradapterregistry = globaladvisoradapterregistry.getinstance();</code>
<code> </code><code>private</code> <code>transient</code> <code>classloader proxyclassloader;</code>
<code> </code><code>private</code> <code>object proxy;</code>
通過jdk代理或者cglib代理,加上攔截器,完成代理對象proxy的建立。
具體過程:
<code>public</code> <code>void</code> <code>afterpropertiesset() {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.target ==</code><code>null</code><code>) {</code>
<code> </code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"property 'target' is required"</code><code>);</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.target</code><code>instanceof</code> <code>string) {</code>
<code> </code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"'target' needs to be a bean reference, not a bean name as value"</code><code>);</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.proxyclassloader ==</code><code>null</code><code>) {</code>
<code> </code><code>this</code><code>.proxyclassloader = classutils.getdefaultclassloader();</code>
<code> </code><code>proxyfactory proxyfactory =</code><code>new</code> <code>proxyfactory();</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.preinterceptors !=</code><code>null</code><code>) {</code>
<code> </code><code>for</code> <code>(object interceptor :</code><code>this</code><code>.preinterceptors) {</code>
<code> </code><code>proxyfactory.addadvisor(</code><code>this</code><code>.advisoradapterregistry.wrap(interceptor));</code>
<code> </code><code>// add the main interceptor (typically an advisor).</code>
<code> </code><code>proxyfactory.addadvisor(</code><code>this</code><code>.advisoradapterregistry.wrap(createmaininterceptor()));</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.postinterceptors !=</code><code>null</code><code>) {</code>
<code> </code><code>for</code> <code>(object interceptor :</code><code>this</code><code>.postinterceptors) {</code>
<code> </code><code>proxyfactory.copyfrom(</code><code>this</code><code>);</code>
<code> </code><code>targetsource targetsource = createtargetsource(</code><code>this</code><code>.target);</code>
<code> </code><code>proxyfactory.settargetsource(targetsource);</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.proxyinterfaces !=</code><code>null</code><code>) {</code>
<code> </code><code>proxyfactory.setinterfaces(</code><code>this</code><code>.proxyinterfaces);</code>
<code> </code><code>else</code> <code>if</code> <code>(!isproxytargetclass()) {</code>
<code> </code><code>// rely on aop infrastructure to tell us what interfaces to proxy.</code>
<code> </code><code>proxyfactory.setinterfaces(</code>
<code> </code><code>classutils.getallinterfacesforclass(targetsource.gettargetclass(),</code><code>this</code><code>.proxyclassloader));</code>
<code> </code><code>this</code><code>.proxy = proxyfactory.getproxy(</code><code>this</code><code>.proxyclassloader);</code>
形式2 使用aop:config結合tx:advice配置:
對容器中符合pointcut的bean都建立出代理對象,通知器為tx:advice建立的事務攔截器。
下面說說對于tx:advice的處理過程:
對于xml配置中的每一個标簽,都會有對應的解析器來完成解析工作,每個解析器都實作了beandefinitionparser接口,用于處理tx:advice的beandefinitionparser則為txadvicebeandefinitionparser:
<code>//此次解析要建立的對象類型為transactioninterceptor即事務攔截器</code>
<code>@override</code>
<code> </code><code>protected</code> <code>class getbeanclass(element element) {</code>
<code> </code><code>return</code> <code>transactioninterceptor.</code><code>class</code><code>;</code>
<code>//該方法就是解析并設定上述要建立的對象的參數</code>
<code> </code><code>protected</code> <code>void</code> <code>doparse(element element, parsercontext parsercontext, beandefinitionbuilder builder) {</code>
<code> </code><code>builder.addpropertyreference(</code><code>"transactionmanager"</code><code>, txnamespacehandler.gettransactionmanagername(element));</code>
<code> </code><code>list txattributes = domutils.getchildelementsbytagname(element, attributes);</code>
<code> </code><code>if</code> <code>(txattributes.size() ></code><code>1</code><code>) {</code>
<code> </code><code>parsercontext.getreadercontext().error(</code>
<code> </code><code>"element <attributes> is allowed at most once inside element <advice>"</code><code>, element);</code>
<code> </code><code>else</code> <code>if</code> <code>(txattributes.size() ==</code><code>1</code><code>) {</code>
<code> </code><code>// using attributes source.</code>
<code> </code><code>element attributesourceelement = (element) txattributes.get(</code><code>0</code><code>);</code>
<code> </code><code>rootbeandefinition attributesourcedefinition = parseattributesource(attributesourceelement, parsercontext);</code>
<code> </code><code>builder.addpropertyvalue(</code><code>"transactionattributesource"</code><code>, attributesourcedefinition);</code>
<code> </code><code>// assume annotations source.</code>
<code> </code><code>builder.addpropertyvalue(</code><code>"transactionattributesource"</code><code>,</code>
<code> </code><code>new</code> <code>rootbeandefinition(annotationtransactionattributesource.</code><code>class</code><code>));</code>
可以看到解析過程其實就是擷取transactionmanager和transactionattributesource,然後設定到transactioninterceptor事務攔截器中。
是以tx:advice标簽其實就是建立了一個transactioninterceptor事務攔截器對象而已。其中transactionattributesource是直接對某些方法進行事務屬性的xml配置,下面則是使用注解來配置某些方法的事務屬性。
形式3:配合@transactional來完成注解式事務
@transactional注解僅僅起到方法的食物屬性的收集,真正的處理程式則是<tx:annotation-driven>在執行,它對那些含有@transactional注解的bean建立代理對象,自動加入transactioninterceptor事務攔截器。我們來看下tx:annotation-driven的源碼處理過程:
還是tx:annotation-driven标簽對應的處理器beandefinitionparser為annotationdrivenbeandefinitionparser:
如下:
<code> </code><code>public</code> <code>beandefinition parse(element element, parsercontext parsercontext) {</code>
<code> </code><code>string mode = element.getattribute(</code><code>"mode"</code><code>);</code>
<code> </code><code>if</code> <code>(</code><code>"aspectj"</code><code>.equals(mode)) {</code>
<code> </code><code>// mode="aspectj"</code>
<code> </code><code>registertransactionaspect(element, parsercontext);</code>
<code> </code><code>// mode="proxy"</code>
<code> </code><code>aopautoproxyconfigurer.configureautoproxycreator(element, parsercontext);</code>
<code> </code><code>return</code> <code>null</code><code>;</code>
<code>/**</code>
<code> </code><code>* inner class to just introduce an aop framework dependency when actually in proxy mode.</code>
<code> </code><code>*/</code>
<code> </code><code>private</code> <code>static</code> <code>class</code> <code>aopautoproxyconfigurer {</code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>configureautoproxycreator(element element, parsercontext parsercontext) {</code>
<code> </code><code>aopnamespaceutils.registerautoproxycreatorifnecessary(parsercontext, element);</code>
<code> </code><code>string txadvisorbeanname = transactionmanagementconfigutils.transaction_advisor_bean_name;</code>
<code> </code><code>if</code> <code>(!parsercontext.getregistry().containsbeandefinition(txadvisorbeanname)) {</code>
<code> </code><code>object elesource = parsercontext.extractsource(element);</code>
<code> </code><code>// create the transactionattributesource definition.</code>
<code> </code><code>rootbeandefinition sourcedef =</code><code>new</code> <code>rootbeandefinition(</code>
<code> </code><code>"org.springframework.transaction.annotation.annotationtransactionattributesource"</code><code>);</code>
<code> </code><code>sourcedef.setsource(elesource);</code>
<code> </code><code>sourcedef.setrole(beandefinition.role_infrastructure);</code>
<code> </code><code>string sourcename = parsercontext.getreadercontext().registerwithgeneratedname(sourcedef);</code>
<code> </code><code>// create the transactioninterceptor definition.</code>
<code> </code><code>rootbeandefinition interceptordef =</code><code>new</code> <code>rootbeandefinition(transactioninterceptor.</code><code>class</code><code>);</code>
<code> </code><code>interceptordef.setsource(elesource);</code>
<code> </code><code>interceptordef.setrole(beandefinition.role_infrastructure);</code>
<code> </code><code>registertransactionmanager(element, interceptordef);</code>
<code> </code><code>interceptordef.getpropertyvalues().add(</code><code>"transactionattributesource"</code><code>,</code><code>new</code> <code>runtimebeanreference(sourcename));</code>
<code> </code><code>string interceptorname = parsercontext.getreadercontext().registerwithgeneratedname(interceptordef);</code>
<code> </code><code>// create the transactionattributesourceadvisor definition.</code>
<code> </code><code>rootbeandefinition advisordef =</code><code>new</code> <code>rootbeandefinition(beanfactorytransactionattributesourceadvisor.</code><code>class</code><code>);</code>
<code> </code><code>advisordef.setsource(elesource);</code>
<code> </code><code>advisordef.setrole(beandefinition.role_infrastructure);</code>
<code> </code><code>advisordef.getpropertyvalues().add(</code><code>"transactionattributesource"</code><code>,</code><code>new</code> <code>runtimebeanreference(sourcename));</code>
<code> </code><code>advisordef.getpropertyvalues().add(</code><code>"advicebeanname"</code><code>, interceptorname);</code>
<code> </code><code>if</code> <code>(element.hasattribute(</code><code>"order"</code><code>)) {</code>
<code> </code><code>advisordef.getpropertyvalues().add(</code><code>"order"</code><code>, element.getattribute(</code><code>"order"</code><code>));</code>
<code> </code><code>parsercontext.getregistry().registerbeandefinition(txadvisorbeanname, advisordef);</code>
<code> </code><code>compositecomponentdefinition compositedef =</code><code>new</code> <code>compositecomponentdefinition(element.gettagname(), elesource);</code>
<code> </code><code>compositedef.addnestedcomponent(</code><code>new</code> <code>beancomponentdefinition(sourcedef, sourcename));</code>
<code> </code><code>compositedef.addnestedcomponent(</code><code>new</code> <code>beancomponentdefinition(interceptordef, interceptorname));</code>
<code> </code><code>compositedef.addnestedcomponent(</code><code>new</code> <code>beancomponentdefinition(advisordef, txadvisorbeanname));</code>
<code> </code><code>parsercontext.registercomponent(compositedef);</code>
首先tx:annotation-driven有一個model屬性,有兩個值 proxy和aspectj。
若為proxy:則代表使用springaop架構進行代理。若為aspectj則由aspectj進行代碼植入。前者不改變原有類的位元組碼,後者将攔截代碼植入原有類的位元組碼中。主要講springaop的代理:
先來看一個執行個體:
再結合源代碼,其實就是建立了一個beanfactorytransactionattributesourceadvisor通知器,advice是transactioninterceptor事務攔截器,pointcut是transactionattributesourcepointcut,如下:
<code>public</code> <code>class</code> <code>beanfactorytransactionattributesourceadvisor</code><code>extends</code> <code>abstractbeanfactorypointcutadvisor {</code>
<code> </code><code>private</code> <code>transactionattributesource transactionattributesource;</code>
<code> </code><code>private</code> <code>final</code> <code>transactionattributesourcepointcut pointcut =</code><code>new</code> <code>transactionattributesourcepointcut() {</code>
<code> </code><code>@override</code>
<code> </code><code>protected</code> <code>transactionattributesource gettransactionattributesource() {</code>
<code> </code><code>return</code> <code>transactionattributesource;</code>
<code> </code><code>};</code>
transactionattributesourcepointcut使用的是匿名類,此時的transactionattributesource 為annotationtransactionattributesource。此pointcut的比對方法為:
<code>abstract</code> <code>class</code> <code>transactionattributesourcepointcut</code><code>extends</code> <code>staticmethodmatcherpointcut</code><code>implements</code> <code>serializable {</code>
<code> </code><code>public</code> <code>boolean</code> <code>matches(method method, class<?> targetclass) {</code>
<code> </code><code>transactionattributesource tas = gettransactionattributesource();</code>
<code> </code><code>return</code> <code>(tas ==</code><code>null</code> <code>|| tas.gettransactionattribute(method, targetclass) !=</code><code>null</code><code>);</code>
即根據類和方法是否能擷取事務屬性,使用annotationtransactionattributesource來擷取,即判斷類或者方法上是否有@transactional等注解,若有該類注解則要對該對象建立出代理對象。