之前在做項目中遇到spring無法進行事務代理問題,最後發現是因爲沒有寫接口,原因當時明白了,看到這篇文章寫的清楚些,轉過來
我們先來分析一下Spring事務管理機制的實現原理。由於Spring內置AOP默認使用動態代理模式實現,我們就先來分析一下動態代理模式的實現方 法。動態代理模式的核心就在於代碼中不出現與具體應用層相關聯的接口或者類引用,如上所說,這個代理類適用於任何接口的實現。下面我們來看一個例子。
public class TxHandler implements InvocationHandler { private Object originalObject; public Object bind(Object obj) { this.originalObject = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; if (!method.getName().startsWith("save")) { UserTransaction tx = null; try { tx = (UserTransaction) (new InitialContext().lookup("java/tx")); result = method.invoke(originalObject, args); tx.commit(); } catch (Exception ex) { if (null != tx) { try { tx.rollback(); } catch (Exception e) { } } } } else { result = method.invoke(originalObject, args); } return result; } }
下面我們來分析一下上述代碼的關鍵所在。
首先來看一下這段代碼:
return Proxy.newProxyInstance( obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
java.lang.reflect.Proxy.newProxyInstance方法根據傳入的接口類型 (obj.getClass.getInterfaces())動態構造一個代理類實例返回,這也說明了爲什麼動態代理實現要求其所代理的對象一定要實現 一個接口。這個代理類實例在內存中是動態構造的,它實現了傳入的接口列表中所包含的所有接口。
再來分析以下代碼:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { …… result = method.invoke(originalObject, args); …… return result; }
InvocationHandler.invoke方法將在被代理類的方法被調用之前觸發。通過這個方法,我們可以在被代理類方法調用的前後進行一些處 理,如代碼中所示,InvocationHandler.invoke方法的參數中傳遞了當前被調用的方法(Method),以及被調用方法的參數。同 時,可以通過method.invoke方法調用被代理類的原始方法實現。這樣就可以在被代理類的方法調用前後寫入任何想要進行的操作。
Spring的事務管理機制實現的原理,就是通過這樣一個動態代理對所有需要事務管理的Bean進行加載,並根據配置在invoke方法中對當前調用的 方法名進行判定,並在method.invoke方法前後爲其加上合適的事務管理代碼,這樣就實現了Spring式的事務管理。Spring中的AOP實 現更爲複雜和靈活,不過基本原理是一致的。