要完全理解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…