• spring---aop(3)---Spring AOP的拦截器链


    写在前面

      时间断断续续,这次写一点关于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 cache设置指定Key过期时间
    Idea Debug多线程不进断点问题处理
    spring cloud gateway使用 uri: lb://方式配置时,服务名的特殊要求
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1067:整数的个数
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1067:整数的个数
    征战蓝桥 —— 2013年第四届 —— C/C++A组第10题——大臣的旅费
    征战蓝桥 —— 2013年第四届 —— C/C++A组第10题——大臣的旅费
    征战蓝桥 —— 2013年第四届 —— C/C++A组第10题——大臣的旅费
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1066:满足条件的数累加
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1066:满足条件的数累加
  • 原文地址:https://www.cnblogs.com/chihirotan/p/7146586.html
Copyright © 2020-2023  润新知