欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

spring——AOP原理及源码五【系列完】,

来源: javaer 分享于  点击 33216 次 点评:260

spring——AOP原理及源码五【系列完】,


前情回顾:

  在上一篇中,通过 wrapIfNecessary 方法,我们获取到了合适的增强器(日志方法)与业务类进行包装,最终返回了我们业务类的代理对象。

  

 

  本篇我们将从业务方法的执行开始,看看增强器(日志方法)是怎么在方法执行的前后和发生异常时被调用的。以及在文章的最后总结整个AOP的执行流程。

 

调试的起点:

给测试方法打上断点,然后一直跳到下一个断点直到执行方法,如下  

 

进入断点:

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


intercept 方法从上往下看:

16~18:获取目标类(注意不是代理对象)

  

 

19:通过目标类和目标方法获取拦截器链

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);


 

重点探究获取拦截器链的过程

进入 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 } getInterceptorsAndDynamicInterceptionAdvice

 

以上代码从上往下看:

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 } proceed

 

3~6:可以看到有一个从-1开始的索引,这是用来记录当前执行次数的(这里的size为5对应我们的五个增强器)

 

 

8~9:每次从拦截器链中获取一个增强器,索引加一

10:判断这个增强器是不是 InterceptorAndDynamicMethodMatcher 类型,我们这里判断不满足,来到了else,返回调用 invoke 方法的结果

 


 

接下来我们进入这个执行过程

invoke方法调用proceed方法

 

 

来到proceed方法继续判断索引大小

 

往下走又来到 invoke 方法,从下图可以看到当前是异常增强器的invoke()

 

进入invoke

先 return 调用 proceed 方法

可以看到下图中 catch 部分,说明如果有出现异常,会在catch部分调用增强器方法,并抛出异常

 

接下来又是调用AfterReturning的invoke过程

 

下图可以看到又调用了proceed 

 

中间的过程也一样,这里就不演示了

最终我们的索引来到末尾

整个过程开始从内到外执行日志方法

开始调用日志方法打印:

 

 

抛出异常

 

 

最终拦截器链调用完毕,得到结果:

 

以上可以看到,整个执行流程是一个递归调用的过程,对之前排好序的拦截器链,通过索引判断界限,一层一层往里调用,最终递归回来一层层执行增强器(日志方法)

 


 

 

AOP总结:

通过@EnableAspectJAutoProxy 注解,给容器中注册 AnnotationAwareAspectJAutoProxyCreator,这个组件是一个后置处理器

会在每一个bean创建之前执行它的后置处理器方法来获取对应增强器,并获取到目标代理对象

在执行切面方法时,通过代理对象和增强器等信息,获取到拦截器链

拦截器链在包装处理后进入执行流程,嵌套调用后执行增强器方法

 

相关文章

    暂无相关文章
相关栏目:

用户点评