一.实验开始前,先写一个切面
@Component
@Aspect
public class ServiceAspect {
@Pointcut("execution(public * com.netty.use.nettyuse.service.LaService.*(..))")
public void webLog(){}
@Around(value = "webLog()")
public Object around(ProceedingJoinPoint pjp) {
try {
System.out.println("Around:方法环绕开始.....");
Object o = pjp.proceed();
System.out.println("Around:方法环绕结束,结果是 :" + o);
return o;
} catch (Throwable e) {
System.out.println(pjp.getSignature() + " 出现异常: "+e.getMessage());
return "";
}
}
@Before(value = "webLog()")
public void before(JoinPoint pjp) {
try {
System.out.println("before方法执行.....");
} catch (Throwable e) {
System.out.println(pjp.getSignature() + " 出现异常: "+e.getMessage());
}
}
@After(value = "webLog()")
public void after(JoinPoint pjp) {
System.out.println("after方法执行.....");
}
@AfterReturning(value = "webLog()")
public void afterReturning(JoinPoint pjp) {
System.out.println("afterReturning方法执行.....");
}
@AfterThrowing(value = "webLog()")
public void afterThrowing(JoinPoint pjp) {
try {
System.out.println("afterThrowing方法执行.....");
} catch (Throwable e) {
System.out.println(pjp.getSignature() + " 出现异常: "+e.getMessage());
}
}
}
该切面中包含了,Around,Before,After,AfterReturning,AfterThrowing类型的通知。
二.责任链中有哪些Advise
我们触发一个切点,debug发现责任链中有如下Advice类,按顺序排列如下:
1.ExposeInvocationInterceptor
2.AspectJAfterThrowingAdvice
3.AfterReturningAdviceInterceptor
4.AspectJAfterAdvice
5.AspectJAroundAdvice
6.MethodBeforeAdviceInterceptor
三.递归调用的过程
责任链的执行核心在ReflectiveMethodInvocation类的proceed方法,如下:
@Override
@Nullable
public Object proceed() throws Throwable {
// 递归调用的出口
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
//调用advise的invoke方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
第一个调用的是ExposeInvocationInterceptor的invoke方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
//形成了递归调用
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
入参mi是ReflectiveMethodInvocation类型,ReflectiveMethodInvocation是MethodInvocation的子类。mi.proceed()形成了递归调用。
下面该调用AspectJAfterThrowingAdvice的invoke方法了。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//递归调用
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
//异常之后,执行异常处理方法
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
AfterReturningAdviceInterceptor和AspectJAfterAdvice的invoke方法,我们这里就不贴代码了,和AspectJAfterThrowingAdvice的处理类似,都是先递归,递归返回之后,才执行程序员自己定义的通知方法。
我们看一下AspectJAroundAdvice的invoke方法:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
//执行Around通知方法
return invokeAdviceMethod(pjp, jpm, null, null);
}
我自己写的Around方法如下:
@Around(value = "webLog()")
public Object around(ProceedingJoinPoint pjp) {
try {
System.out.println("Around:方法环绕开始.....");
//递归调用
Object o = pjp.proceed();
System.out.println("Around:方法环绕结束,结果是 :" + o);
return o;
} catch (Throwable e) {
System.out.println(pjp.getSignature() + " 出现异常: "+e.getMessage());
return "";
}
}
它会先执行环绕之前的代码,再进行递归,最后再执行环绕之后的代码。这里执行递归的时候,还剩下MethodBeforeAdviceInterceptor(before通知)还没执行,把before通知执行之后,执行到递归的出口:
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
因为currentInterceptorIndex是从-1开始的,把所有的Interceptor都调用一次后
currentInterceptorIndex==this.interceptorsAndDynamicMethodMatchers.size() - 1。
这里invokeJoinpoint(),目标方法被执行。