Spring AOP 中的责任链模式

缘起

最近在研读Spring AOP 的源码,在【1】的”拦截器链如何执行”小节就遇到了责任链设计模式. 其实Struts这种webmvc框架中也用到了这种设计模式.

如果想了解那部分的源码的话,可以参考【1】,这里仅仅抽象出一个小demo而已.

分析

项目工程结构如下

测试类 App.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package test;

import java.util.ArrayList;
import java.util.List;

import interceptor.MethodInterceptor;
import interceptor.impl.MethodInterceptorA;
import interceptor.impl.MethodInterceptorB;
import interceptor.impl.MethodInterceptorC;
import invocation.MethodInvocation;

public class App {
public static void main(String[] args) throws Throwable {
Human human = new Human();
List<MethodInterceptor> chains = new ArrayList<>();
chains.add(new MethodInterceptorA());
chains.add(new MethodInterceptorB());
chains.add(new MethodInterceptorC());
MethodInvocation invocation = new MethodInvocation(human, human.getClass().getDeclaredMethod("givebirth"),
chains);
/*
护士A来处理
护士B来处理
护士C来处理
生啦~
*/
invocation.proceed();
}
}

目标类 Human.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package test;

/**
* 目标类
*
* @author yfs
*
*/
public class Human {

public void givebirth() {
System.out.println("生啦~");
}
}

执行上下文 MethodInvocation.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package invocation;

import java.lang.reflect.Method;
import java.util.List;

import interceptor.MethodInterceptor;

/**
* 执行上下文
*
* @author yfs
*
*/
public class MethodInvocation {

/** 目标对象 */
private Object target;

/** 目标方法 */
private Method method;

/** 目标方法的参数 */
private Object[] args;

/** 拦截器链(其实这里可以换成更抽象的迭代器) */
private List<MethodInterceptor> chains;

/** 当前在哪个拦截器位置 */
private int currentIndex = -1;

public MethodInvocation(Object target, Method method, List<MethodInterceptor> chains, Object... args) {
this.target = target;
this.method = method;
this.chains = chains;
this.args = args;
}

/**
* 行进方法(proceed这个名字起的真好, 整个过程就在chains上行进)
*
* @return
*/
public Object proceed() throws Throwable {
// 如果已经到达了最后的拦截器(很容易想明白,比如当前拦截器链式空的)
if (currentIndex == chains.size() - 1) {
return method.invoke(target, args);
}
MethodInterceptor interceptor = chains.get(++currentIndex); // 获取当前拦截器
return interceptor.invoke(this);
}

}

拦截器接口 MethodInterceptor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package interceptor;

import invocation.MethodInvocation;

/**
* 拦截器接口
*
* @author yfs
*
*/
public interface MethodInterceptor {

/**
* 本拦截器要做的事情
*
* @param mi
* 执行上下文
* @return
*/
public Object invoke(MethodInvocation mi) throws Throwable;
}

拦截器实现类A MethodInterceptorA.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package interceptor.impl;

import interceptor.MethodInterceptor;
import invocation.MethodInvocation;

public class MethodInterceptorA implements MethodInterceptor {

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("护士A来处理"); // 如果交换这两行代码,就是拦截器链中倒序执行
return mi.proceed();
}

}

拦截器实现类A MethodInterceptorA.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package interceptor.impl;

import interceptor.MethodInterceptor;
import invocation.MethodInvocation;

public class MethodInterceptorB implements MethodInterceptor {

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("护士B来处理");
return mi.proceed();
}

}

拦截器实现类C MethodInterceptorC.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package interceptor.impl;

import interceptor.MethodInterceptor;
import invocation.MethodInvocation;

public class MethodInterceptorC implements MethodInterceptor {

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("护士C来处理");
return mi.proceed();
}

}

上述代码的核心就是——每个拦截器要做的业务逻辑由自己写,调用的mi.proceed()纯粹就是让chains拦截器链继续往下执行而已(因为在MethodInvocation中currentIndex会++)。

参考

【1】https://yfsyfs.github.io/2019/06/13/spring-AOP-%E6%B3%A8%E8%A7%A3%E5%8E%9F%E7%90%86/

【1】