写在前面

  时间断断续续,这次写一点关于spring aop拦截器链的记载。至于如何获取spring的拦截器,前一篇博客已经写的很清楚(spring---aop(2)---Spring AOP的JDK动态代理

获取拦截器链

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
       //获取拦截器链  
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
if (chain.isEmpty()) {
// 如果拦截器链为空,则执行目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// 封装拦截器链的执行方法
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 拦截器链执行
retVal = invocation.proceed();
}
     ...
}

ReflectiveMethodInvocation 的结构

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
protected final Object proxy;
protected final Object target;
protected final Method method;
protected Object[] arguments;
private final Class<?> targetClass;
private Map<String, Object> userAttributes;
//拦截器链
protected final List<?> interceptorsAndDynamicMethodMatchers;
   //起始基数 默认为-1
private int currentInterceptorIndex = -1;

   @Override//拦截器执行入口
public Object proceed() throws Throwable {
// 如果自增系数和拦截器链中拦截器数量相同(则代表,拦截器依次执行完毕)
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
       //拦截器执行完毕,执行目标方法;
return invokeJoinpoint();
}
     //根据起始基数,依次获对应的拦截器。(每次获取拦截器,起始基数都自增一次)
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
     //这里获取的具体拦截器只会是两种类型(InterceptorAndDynamicMethodMathcher或者MethodInterceptor)      InterceptorAndDynamicMethodMathcher:拦截器的动态方法匹配(这个用的比较少)
MethodInterceptor :方法拦截器(我们的aop拦截基本上都是methodInterceptor)
     if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 具体的拦截器执行执行自己的invoke方法,将拦截器链传到里面去了。类似一个链,做递归调用,最有一个拦截器执行完毕(自增系数会和拦截器数量相同,执行目标方法),最后每一个拦截器依次返回,拦截器链执行完毕
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
}
实现类 ReflectiveMethodInvocation 实现接口 ProxyMethodInvocation 继承接口 MethodInvocation 继承接口 Invocation 继承接口 Joinpoint
接口 MethodInterceptor 继承接口 Interceptor 继承接口 Advice

可以看看 MethodInterceptor 自己的抽象方法
public interface MethodInterceptor extends Interceptor {
//拦截器就是通过这个方法的实现,一次执行拦截器链,直到拦截器链中的拦截器执行完毕
Object invoke(MethodInvocation invocation) throws Throwable;
}

看一个 MethodInterceptor 的具体实现 : TransactionInterceptor(事务通知)

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

    @Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
//先准备事物的环境,执行事物执行的相关操作,具体见之前的博客 (spring---transaction(1)---源代码分析(事务的拦截器TransactionInterceptor))
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
          //准备好环境之后,回调拦截器链,拦截器链中的起始基数自增,执行下一个拦截器的invoke方法。如果这是最后一个拦截器,那么拦截器链中的起始基数和拦截器数相同,执行目标方法
return invocation.proceed();
}
});
}
}

再看一个 MethodInterceptor 的实现:MethodBeforeAdviceInterceptor(前置通知)

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
   private MethodBeforeAdvice advice;
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
     //执行前置通知的具体方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
     //执行完成之后,回调拦截器链,执行下一个拦截器的invoke方法
return mi.proceed();
}
}

再看一个 MethodInterceptor 的实现:AspectJAfterAdvice(后置通知)

public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {

    @Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
        //因为是后置通知,直接调用拦截器链的下一个拦截器。如果拦截器全部调用完毕,会执行目标方法
return mi.proceed();
}
finally {
       //后置通知具体方法执行。到这里,所有的拦截器以及全部执行完毕,且目标方法已经执行。所有在这里执行后置拦截器的后置方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}

再看一个 MethodInterceptor 的实现:AspectJAfterThrowingAdvice(环绕通知)

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {

    @Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
       //因为是环绕通知,直接调用拦截器链的下一个拦截器。将目标方法的执行方法try cathch 代码块中
return mi.proceed();
}
catch (Throwable t) {
        //判断是否是目标方法的异常信息
if (shouldInvokeOnThrowing(t)) {
          //如果目标方法在执行的过程中 抛出异常,则执行环绕通知的异常方法。  
invokeAdviceMethod(getJoinPointMatch(), null, t);
}
        //继续抛出异常,不影响正常的业务逻辑
throw t;
}
}
}

一张图清晰解释拦截器原则

总结一下:

  spring的aop设计,并不是所有的通知对象一产生出来就是拦截器,spring是将所有的通知转化为了拦截器(MethodInterceptor 的子类)。中间有经过转换,到了拦截器链中,作为拦截器统一处理。这次先不写转换为拦截器的过程

spring---aop(3)---Spring AOP的拦截器链的更多相关文章

  1. Spring异步调用原理及SpringAop拦截器链原理

    一.Spring异步调用底层原理 开启异步调用只需一个注解@EnableAsync @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTI ...

  2. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  3. 2017.3.31 spring mvc教程(三)拦截器

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  4. Spring Boot项目中如何定制拦截器

    本文首发于个人网站:Spring Boot项目中如何定制拦截器 Servlet 过滤器属于Servlet API,和Spring关系不大.除了使用过滤器包装web请求,Spring MVC还提供Han ...

  5. 33、[源码]-AOP原理-获取拦截器链-MethodInterceptor

    33.[源码]-AOP原理-获取拦截器链-MethodInterceptor

  6. java 动态代理—— Mybaties 拦截器链基本原理实现

    1.摘要 Mybaties 中有个分页插件,之前有特意的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,从了解中得知分页插件 ...

  7. JdkDynamicAopProxy 拦截器链的获得与递归执行

    JdkDynamicAopProxy类的invoke方法 1.获得拦截器链 List<Object> chain = this.advised.getInterceptorsAndDyna ...

  8. SpringBoot系列(十一)拦截器与拦截器链的配置与使用详解,你知道多少?

    往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)web静 ...

  9. 我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器

    回到目录 AOP面向切面的编程,也称面向方面的编程,我更青睐于前面的叫法,将一个大系统切成多个独立的部分,而这个独立的部分又可以方便的插拔在其它领域的系统之中,这种编程的方式我们叫它面向切面,而这些独 ...

随机推荐

  1. bzoj 1083 繁忙的都市

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1083 题解: 在bzoj里能遇到如此如此水的题真是不容易…… 乍一看好像有点吓人,其实是一 ...

  2. Django-ORM简介

    ORM简介 MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库 ORM是“对象-关系-映射”的简称 ...

  3. overridePendingTransition()使用

    实现两个 Activity 切换时的动画.在Activity中使用有两个参数:进入动画和出去的动画. 注意1.必须在 StartActivity()  或 finish() 之后立即调用.2.而且在 ...

  4. unity 代码有调整,重新导出 iOS 最烦的就是 覆盖导出后项目不能打开

    unity  代码有调整,重新导出 iOS 最烦的就是 覆盖导出后项目不能打开,原因是 editor 里面的脚本,破坏了 Unity-iPhone.xcodeproj 里面的结构,具体是什么原因,也不 ...

  5. 列表CListCtrl类使用

    CListCtrl是列表控件类,列表控件的每一行叫做一个item,每一列叫做一个subitem.每一行和每一列都有个ID号,可以确定唯一的单元格. 最近使用了这个控件,有心得总结如下: (Dialog ...

  6. (三)HttpClient 抓取图片

    第一节: HttpClient 抓取图片 这里pom.xml需要用到io输入输出: <dependency> <groupId>commons-io</groupId&g ...

  7. DotNetOpenAuth实践之搭建验证服务器

    系列目录: DotNetOpenAuth实践系列(源码在这里) DotNetOpenAuth是OAuth2的.net版本,利用DotNetOpenAuth我们可以轻松的搭建OAuth2验证服务器,不废 ...

  8. 计算Python代码运行时间长度方法

    在代码中有时要计算某部分代码运行时间,便于分析. import time start = time.clock() run_function() end = time.clock() print st ...

  9. PHP学习日记 Windows配置PHP+Nginx+自动化脚本

    Windows配置PHP+Nginx+自动化脚本 安装与配置 PHP 下载PHP:传送门 选择合适的版本下载 尽量选Thread Safe 配置PHP: 解压后在文件夹中找到php.ini-devel ...

  10. Hadoop整理一(初识Hadoop)

    一.要点 1.Hadoop目的是让多台计算机同时解决一个问题 2.HDFS(Hadoop Distributed File System 分布式存储系统)是一个分布式文件系统,有目录,目录下可以存储文 ...