前情回顾:
在上一篇中,通过 wrapIfNecessary 方法,我们获取到了合适的增强器(日志方法)与业务
类进行包装,最终返回了我们业务类的代理对象。
本篇我们将从业务方法的执行开始,看看增强器(日志方法)是怎么在方法执行的前后和发
生异常时被调用的。以及在文章的最后总结整个AOP的执行流程。
1、调试的起点:
给测试方法打上断点,然后一直跳到下一个断点直到执行方法,如下
接着进入方法,会被intercept方法拦截
进入断点:
1 @Override
2 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
3 Object oldProxy = null;
4 boolean setProxyContext = false;
5 Class<?> targetClass = null;
6 Object target = null;
7 try {
8 if (this.advised.exposeProxy) {
9 // Make invocation available if necessary.
10 oldProxy = AopContext.setCurrentProxy(proxy);
11 setProxyContext = true;
12 }
13 // May be null. Get as late as possible to minimize the time we
14 // "own" the target, in case it comes from a pool...
15 target = getTarget();
16 if (target != null) {
17 targetClass = target.getClass();
18 }
19 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
20 Object retVal;
21 // Check whether we only have one InvokerInterceptor: that is,
22 // no real advice, but just reflective invocation of the target.
23 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
24 // We can skip creating a MethodInvocation: just invoke the target directly.
25 // Note that the final invoker must be an InvokerInterceptor, so we know
26 // it does nothing but a reflective operation on the target, and no hot
27 // swapping or fancy proxying.
28 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
29 retVal = methodProxy.invoke(target, argsToUse);
30 }
31 else {
32 // We need to create a method invocation...
33 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
34 }
35 retVal = processReturnType(proxy, target, method, retVal);
36 return retVal;
37 }
38 finally {
39 if (target != null) {
40 releaseTarget(target);
41 }
42 if (setProxyContext) {
43 // Restore old proxy.
44 AopContext.setCurrentProxy(oldProxy);
45 }
46 }
47 }
intercept 方法从上往下看:
16~18:获取目标类(注意不是代理对象)
19:通过目标类和目标方法获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
2、重点探究获取拦截器链的过程
进入 getInterceptorsAndDynamicInterceptionAdvice
继续进入 this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass)
1 @Override
2 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
3 Advised config, Method method, Class<?> targetClass) {
4
5 // This is somewhat tricky... We have to process introductions first,
6 // but we need to preserve order in the ultimate list.
7 List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
8 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
9 boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
10 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
11
12 for (Advisor advisor : config.getAdvisors()) {
13 if (advisor instanceof PointcutAdvisor) {
14 // Add it conditionally.
15 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
16 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
17 MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
18 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
19 if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
20 if (mm.isRuntime()) {
21 // Creating a new object instance in the getInterceptors() method
22 // isn't a problem as we normally cache created chains.
23 for (MethodInterceptor interceptor : interceptors) {
24 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
25 }
26 }
27 else {
28 interceptorList.addAll(Arrays.asList(interceptors));
29 }
30 }
31 }
32 }
33 else if (advisor instanceof IntroductionAdvisor) {
34 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
35 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
36 Interceptor[] interceptors = registry.getInterceptors(advisor);
37 interceptorList.addAll(Arrays.asList(interceptors));
38 }
39 }
40 else {
41 Interceptor[] interceptors = registry.getInterceptors(advisor);
42 interceptorList.addAll(Arrays.asList(interceptors));
43 }
44 }
45
46 return interceptorList;
47 }
以上代码从上往下看:
5:创建拦截器链
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length)
12~32:
- 遍历所有增强器
- 经过一系列判断,将增强器放入interceptorList中 :
- interceptorList.addAll(Arrays.asList(interceptors))
46:将拦截器链返回
接下来将拦截器链返回,并存入缓存中
最后将拦截器链返回
这就是拦截器链获取的过程
接下来来到 intercept 方法的真正执行部分:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
通过new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy) 获取到方法拦截器链
一进来先调用父类方法:
设置好代理对象、目标类、目标方法、拦截器链等一系列属性:
接着一路返回后调用 proceed 方法进行执行:
1 @Override
2 public Object proceed() throws Throwable {
3 // We start with an index of -1 and increment early.
4 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
5 return invokeJoinpoint();
6 }
7
8 Object interceptorOrInterceptionAdvice =
9 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
10 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
11 // Evaluate dynamic method matcher here: static part will already have
12 // been evaluated and found to match.
13 InterceptorAndDynamicMethodMatcher dm =
14 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
15 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
16 return dm.interceptor.invoke(this);
17 }
18 else {
19 // Dynamic matching failed.
20 // Skip this interceptor and invoke the next in the chain.
21 return proceed();
22 }
23 }
24 else {
25 // It's an interceptor, so we just invoke it: The pointcut will have
26 // been evaluated statically before this object was constructed.
27 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
28 }
29 }
3~6:可以看到有一个从-1开始的索引,这是用来记录当前执行次数的(这里的size为5对应我们的五个增强器)
8~9:每次从拦截器链中获取一个增强器,索引加一
10:判断这个增强器是不是 InterceptorAndDynamicMethodMatcher 类型,我们这里判断不满足,来到了else,返回调用 invoke 方法的结果
接下来我们进入这个执行过程
invoke方法调用proceed方法
来到proceed方法继续判断索引大小
往下走又来到 invoke 方法,从下图可以看到当前是异常增强器的invoke()
进入invoke
先 return 调用 proceed 方法
可以看到下图中 catch 部分,说明如果有出现异常,会在catch部分调用增强器方法,并抛出异常
接下来又是调用AfterReturning的invoke过程
下图可以看到又调用了proceed
中间的过程也一样,这里就不演示了
最终我们的索引来到末尾
整个过程开始从内到外执行日志方法
开始调用日志方法打印:
抛出异常
最终拦截器链调用完毕,得到结果:
以上可以看到,整个执行流程是一个递归调用的过程,对之前排好序的拦截器链,通过索引判断界限,一层一层往里调用,最终递归回来一层层执行增强器(日志方法)
3、AOP总结:
通过@EnableAspectJAutoProxy 注解,给容器中注册 AnnotationAwareAspectJAutoProxyCreator,这个组件是一个后置处理器
会在每一个bean创建之前执行它的后置处理器方法来获取对应增强器,并获取到目标代理对象
在执行切面方法时,通过代理对象和增强器等信息,获取到拦截器链
拦截器链在包装处理后进入执行流程,嵌套调用后执行增强器方法
aop uml图
以下UML图是我对AOP的理解,如果有不对之处,欢迎大家指出