要完全理解Spring AOP首先要理解AOP的核心概念和术语,这些术语并不是Spring指定的,而且很不幸,这些术语并不能直观理解,但是,如果Spring使用自己的术语,那将更加令人困惑。
proxy-target-class="true" ,完全使用CGLIB动态代理。 枚举AdviceMode 来设置。 在这里我们 不再展示测试代码 ,而是通过简单的代码来 模拟aspect advice的执行过程 。
尽管Spring AOP是通过 动态代理 来实现的,但是我们可以绕过代理,直接模拟出它的执行过程,示例代码:
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的 执行顺序,结果如下:
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的执行顺序 ,有两种方式:
Aspect 类添加 注解 :org.springframework.core.annotation.Order,使用注解 value 属性指定优先级。
Aspect 类实现 接口 :org.springframework.core.Ordered,实现 Ordered 接口的 getOrder() 方法。
其中,数值越低,表明优先级越高, @Order 默认为最低优先级,即最大数值:
/** * 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…