要徹底理解Spring AOP首先要理解AOP的核心概念和術語,這些術語並非Spring指定的,並且很不幸,這些術語並不能直觀理解,可是,若是Spring使用本身的術語,那將更加使人困惑。html
proxy-target-class="true"
,徹底使用CGLIB動態代理。枚舉AdviceMode
來設置。在這裏咱們再也不展現測試代碼,而是經過簡單的代碼來模擬aspect advice的執行過程。java
儘管Spring AOP是經過動態代理
來實現的,可是咱們能夠繞過代理,直接模擬出它的執行過程,示例代碼:spring
package doubt;
public class AspectAdviceInvokeProcess {
public static void main(String[] args){
try {
//正常執行
AspectInvokeProcess(false);
System.out.println("=====分割線=====");
//異常執行
AspectInvokeProcess(true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * 切面執行過程 * @param isException * @throws Exception */
public static void AspectInvokeProcess(boolean isException) throws Exception{
try {
try {
aroundAdvice(isException);
} finally {
afterAdvice();
}
afterReturningAdvice();
return;
} catch (Exception e) {
afterThrowingAdvice(e);
throw e;
return;
}
}
/** * 環繞加強 * @param isException * @throws Exception */
private static void aroundAdvice(boolean isException) throws Exception {
System.out.println("around before advice");
try {
JoinPoint_Proceed(isException);
} finally {
System.out.println("around after advice");
}
}
/** * 編織後的接入點執行過程 * @param isException */
public static void JoinPoint_Proceed(boolean isException){
beforeAdvice();
targetMethod(isException);
}
/** * 前置加強 */
private static void beforeAdvice() {
System.out.println("before advice");
}
/** * 目標方法 * @param isException */
private static void targetMethod(boolean isException) {
System.out.println("target method 執行");
if(isException)
throw new RuntimeException("異常發生");
}
/** * 後置加強 */
private static void afterAdvice() {
System.out.println("after advice");
}
/** * 正常返回加強 */
private static void afterReturningAdvice() {
System.out.println("afterReturning");
}
/** * 異常返回加強 * @param e * @throws Exception */
private static void afterThrowingAdvice(Exception e) throws Exception {
System.out.println("afterThrowing:"+e.getMessage());
}
}
複製代碼
上述代碼的執行結果,直接體現了同一apsect中不一樣advice的
執行順序,結果以下:bash
around before advice
before advice
target method 執行
around after advice
after advice
afterReturning
===============分割線==============
around before advice
before advice
target method 執行
around after advice
after advice
afterThrowing:異常發生
java.lang.RuntimeException: 異常發生
複製代碼
得出結論: 框架
詳情可見,《Spring官方文檔》 docs.spring.io/spring/docs…測試
Spring AOP經過指定aspect
的優先級,來控制不一樣aspect,advice的執行順序
,有兩種方式:this
Aspect 類添加註解:org.springframework.core.annotation.Order,使用註解value
屬性指定優先級。spa
Aspect 類實現接口:org.springframework.core.Ordered,實現 Ordered 接口的 getOrder() 方法。代理
其中,數值越低,代表優先級越高,@Order 默認爲最低優先級,即最大數值:code
/** * Useful constant for the lowest precedence value. * @see java.lang.Integer#MAX_VALUE */
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
複製代碼
最終,不一樣aspect,advice的執行順序
:
以下圖所示:
先入後出,後入先出
同一aspect,相同advice的執行順序
並不能直接肯定,並且 @Order 在advice
方法上也無效,可是有以下兩種變通方式:
Spring事務管理(Transaction Management),也是基於Spring AOP。
在Spring AOP的使用中,有時咱們必須明確自定義aspect的優先級低於或高於事務切面(Transaction Aspect),因此咱們須要知道:
LOWEST_PRECEDENCE = Integer.MAX_VALUE
複製代碼
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport implements DisposableBean {
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
setTransactionAttributeSource(tas);
}
@SuppressAjWarnings("adviceDidNotMatch")
Object around(final Object txObject): transactionalMethodExecution(txObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
try {
return invokeWithinTransaction(methodSignature.getMethod(), txObject.getClass(), new InvocationCallback() {
public Object proceedWithInvocation() throws Throwable {
return proceed(txObject);
}
});
}
catch (RuntimeException ex) {
throw ex;
}
catch (Error err) {
throw err;
}
catch (Throwable thr) {
Rethrower.rethrow(thr);
throw new IllegalStateException("Should never get here", thr);
}
}
}
複製代碼
@EnableTransactionManagement
和 <tx:annotation-driven/>
中的, order
屬性來修改事務切面的優先級。 詳情可見,《Spring官方文檔》docs.spring.io/spring/docs…