2021.4.18
目录
- 责任链模式
- 自己简单实现一个责任链模式
- 分析代码
- SpringAOP源码
责任链模式
一个对象被多个拦截器拦截处理时,我们称这样的设计模式为责任链模式。
重点是其中在多个拦截器中,对象都是同一个,这样做能让处理始终围绕一开始的对象。
责任链模式在Filter过滤器和Spring的Interceptor里面都常常用到。
自己简单实现一个责任链模式
先画出UML的类图,大致的关系如下:
可以看出上面有三个接口,三个实现类。
接口代码分别是:
连接点接口
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中经常看到的结果:
分析代码
在上述代码中,重点需要理解的是两个地方:
- 拦截器列表的取值。
- 责任链模式本质是个递归。
在上文代码中,我们给拦截器列表增加了两个元素,分别是:
- 前置增强拦截器(对应下标为0)
- 后置增强拦截器(对应下标为1)
第一步:
第二步:
第三步:此时,与第一步大同小异,但是此时index已经发生了变化。
第四步:
这里的第四步与第二步类似。
第五步
非常关键的一步,在这一步里,才真正调用了被代理类原本的方法。
第六步:递归回溯,完成整个拦截过程。
完成了上面的理解,我们再看一下SpringAOP调用代理对象的方法时的图
感觉就非常相像了。
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);
}
}
}
有关这段源码的理解,已经在上方注释里面添加。