2021.4.18


目录

  • 责任链模式
  • 自己简单实现一个责任链模式
  • 分析代码
  • SpringAOP源码


责任链模式

一个对象被多个拦截器拦截处理时,我们称这样的设计模式为责任链模式。
重点是其中在多个拦截器中,对象都是同一个,这样做能让处理始终围绕一开始的对象。
责任链模式在Filter过滤器和Spring的Interceptor里面都常常用到。

自己简单实现一个责任链模式

先画出UML的类图,大致的关系如下:

java 责任链模式超过三个对象 spring 责任链模式_拦截器


可以看出上面有三个接口,三个实现类。

接口代码分别是:

连接点接口

public interface JointPoint {
    Object proceed() throws Throwable;
}

方法调用接口(为空)

public interface MethodInvocation extends JointPoint{

}

方法拦截器接口

public interface MethodInterceptor {
    Object invoke(MethodInvocation mi) throws Throwable;
}

一共有三个实现类
分别是两个增强:一个前置增强,一个后置增强

public class BeforeMethodInterceptor implements MethodInterceptor{
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        System.out.println("在这里调用前置方法");
        return mi.proceed();
    }
}
public class AspectJAfterAdvice implements MethodInterceptor{
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object var = null;
        try{
            var = mi.proceed();
        }finally {
            System.out.println("执行了后置方法");
        }
        return var;
    }
}

一个中间类,用于处理一个接一个的拦截器

public class ReflectiveMethodInvocation implements MethodInvocation{

    List<MethodInterceptor> methodInterceptors;

    public ReflectiveMethodInvocation(List<MethodInterceptor> methodInterceptors) {
        this.methodInterceptors = methodInterceptors;
    }


    private  int index = -1;

    @Override
    public Object proceed() throws Throwable {
        Object var = null;
        if(index == this.methodInterceptors.size()-1){
            System.out.println("调用被代理的原本方法");
        }else{
            methodInterceptors.get(++index).invoke(this);
        }
        return var;
    }
}

有了上面三个类,那么我们就可以来测试一下了。测试代码如下:

public class test {
    public static void main(String[] args) throws Throwable{
        List<MethodInterceptor> lists = new ArrayList<>();
        //后置增强
        AspectJAfterAdvice aspectJAfterAdvice = new AspectJAfterAdvice();
        //前置增强
        BeforeMethodInterceptor beforeMethodInterceptor = new BeforeMethodInterceptor();
        lists.add(aspectJAfterAdvice);
        lists.add(beforeMethodInterceptor);

        ReflectiveMethodInvocation reflectiveMethodInvocation = new ReflectiveMethodInvocation(lists);
        reflectiveMethodInvocation.proceed();
    }
}

结果就是我们在SpringAOP中经常看到的结果:

java 责任链模式超过三个对象 spring 责任链模式_sed_02

分析代码

在上述代码中,重点需要理解的是两个地方:

  • 拦截器列表的取值。
  • 责任链模式本质是个递归。

在上文代码中,我们给拦截器列表增加了两个元素,分别是:

  • 前置增强拦截器(对应下标为0)
  • 后置增强拦截器(对应下标为1)

第一步:

java 责任链模式超过三个对象 spring 责任链模式_java 责任链模式超过三个对象_03


第二步:

java 责任链模式超过三个对象 spring 责任链模式_责任链模式_04


第三步:此时,与第一步大同小异,但是此时index已经发生了变化。

java 责任链模式超过三个对象 spring 责任链模式_责任链模式_05


第四步:

这里的第四步与第二步类似。

java 责任链模式超过三个对象 spring 责任链模式_java 责任链模式超过三个对象_06

第五步

非常关键的一步,在这一步里,才真正调用了被代理类原本的方法。

java 责任链模式超过三个对象 spring 责任链模式_责任链模式_07

第六步:递归回溯,完成整个拦截过程。

java 责任链模式超过三个对象 spring 责任链模式_java 责任链模式超过三个对象_08


完成了上面的理解,我们再看一下SpringAOP调用代理对象的方法时的图

java 责任链模式超过三个对象 spring 责任链模式_sed_09

感觉就非常相像了。

SpringAOP源码

JdkDynamicAopProxy类中的invoke方法源码如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;
 
        Integer var10;
        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                Boolean var20 = this.equals(args[0]);
                return var20;
            }
 
            if (this.hashCodeDefined || !AopUtils.isHashCodeMethod(method)) {
                if (method.getDeclaringClass() == DecoratingProxy.class) {
                    Class var18 = AopProxyUtils.ultimateTargetClass(this.advised);
                    return var18;
                }
 
                Object retVal;
                if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                    return retVal;
                }
 
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
 
                target = targetSource.getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
 
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                if (chain.isEmpty()) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                } else {
                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    retVal = invocation.proceed();
                }
 
                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    retVal = proxy;
                } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                    throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
                }
 
                Object var13 = retVal;
                return var13;
            }
 
            var10 = this.hashCode();
        } finally {
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
 
            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }
 
        }
 
        return var10;
    }

在上面只看源码这一段

MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();

这个proceed里面究竟是什么呢?

public Object proceed() throws Throwable {
		//这里就是拦截器列表,index到最后就调用被代理类的方法
		//this.invokeJoinpoint()
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
        	//这里从拦截器列表中获取一个增强
        	//这里的拦截器列表顺序由SpringAOP的外层拦截器决定。
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            //判断这个增强是否实现了MethodMatcher接口
            //也就是AOP里面的切点
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            	//如果实现了接口,就要进行强制类型转换
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                //如果实现了MethodMatcher接口
                //如果切点跟目前的拦截器匹配,就调用拦截器,从拦截器里面进行递归
                //如果切点跟目前的拦截器不匹配,就直接进行递归。
                return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
            	//如果没有实现MethodMatcher接口,直接进入拦截器进行递归
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

有关这段源码的理解,已经在上方注释里面添加。