前言
-
这个系列主要讲优秀的开源框架对于责任链这个设计模式的运用,对于好的设计,我们关键是学习他的思想并运用在我们的编码中。
-
这个系列的所有代码都是我根据源码提炼之后的代码,不依赖原项目或框架,可以直接跑。
-
我不会讲每个具体是如何实现的,如果你觉得光看代码比较吃力,那么可以将代码复制下来,自己多运行几遍,我相信你一定能掌握。
-
欢迎访问我的个人网站,里面有超多开源组件和项目,另外还有付费项目和博客,地址:https://openbytecode.com/
-
上一小节我们分析了 Tomcat 的 Filter 设计,这一小节我们来分析 SpringMVC 的 Interceptor 设计
-
本系列 Github 地址:https://github.com/lijunping365/Open-Design
SpringMVC 之 Interceptor
下面的代码是我对 SpringMVC 的 Interceptor 提炼之后的核心代码。
- 拦截器接口
public interface HandlerInterceptor {
default boolean preHandle(HttpRequest request, HttpResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpRequest request, HttpResponse response, Object handler, Object obj) throws Exception {
}
default void afterCompletion(HttpRequest request, HttpResponse response, Object handler, Exception ex) throws Exception {
}
}
参数
public class HttpRequest {
}
public class HttpResponse {
}
下面三个类主要对拦截器进行排序和生效条件设置
public class InterceptorRegistry {
private final List<InterceptorRegistration> registrations = new ArrayList<>();
/**
* Adds the provided {@link org.springframework.web.servlet.HandlerInterceptor}.
* @param interceptor the interceptor to add
* @return an {@link InterceptorRegistration} that allows you optionally configure the
* registered interceptor further for example adding URL patterns it should apply to.
*/
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
this.registrations.add(registration);
return registration;
}
/**
* Return all registered interceptors.
*/
public List<Object> getInterceptors() {
return this.registrations.stream()
.sorted(INTERCEPTOR_ORDER_COMPARATOR)
.map(InterceptorRegistration::getInterceptor)
.collect(Collectors.toList());
}
private static final Comparator<Object> INTERCEPTOR_ORDER_COMPARATOR =
OrderComparator.INSTANCE.withSourceProvider(object -> {
if (object instanceof InterceptorRegistration) {
return (Ordered) ((InterceptorRegistration) object)::getOrder;
}
return null;
});
}
public class InterceptorRegistration {
private final HandlerInterceptor interceptor;
private List<String> includeCondition;
private List<String> excludeCondition;
private int order = 0;
public InterceptorRegistration(HandlerInterceptor interceptor) {
this.interceptor = interceptor;
}
public InterceptorRegistration order(int order) {
this.order = order;
return this;
}
protected int getOrder() {
return this.order;
}
protected Object getInterceptor() {
if (this.includeCondition == null && this.excludeCondition == null) {
return this.interceptor;
} else {
return new MappedInterceptor(includeCondition, excludeCondition, this.interceptor);
}
}
public InterceptorRegistration addIncludeConditions(String... conditions) {
return this.addIncludeConditions(Arrays.asList(conditions));
}
public InterceptorRegistration addIncludeConditions(List<String> conditions) {
this.includeCondition = this.includeCondition != null ? this.includeCondition : new ArrayList(conditions.size());
this.includeCondition.addAll(conditions);
return this;
}
public InterceptorRegistration addExcludeConditions(String... patterns) {
return this.addExcludeConditions(Arrays.asList(patterns));
}
public InterceptorRegistration addExcludeConditions(List<String> patterns) {
this.excludeCondition = this.excludeCondition != null ? this.excludeCondition : new ArrayList(patterns.size());
this.excludeCondition.addAll(patterns);
return this;
}
}
public class MappedInterceptor implements HandlerInterceptor{
private final List<String> includeConditions;
private final List<String> excludeConditions;
private final HandlerInterceptor interceptor;
public MappedInterceptor(List<String> includeConditions, List<String> excludeConditions, HandlerInterceptor interceptor) {
this.includeConditions = includeConditions;
this.excludeConditions = excludeConditions;
this.interceptor = interceptor;
}
public boolean matches(String parameter) {
if (StringUtils.isBlank(parameter)){
return false;
}
return includeConditions.contains(parameter) && !excludeConditions.contains(parameter);
}
public HandlerInterceptor getInterceptor() {
return interceptor;
}
}
拦截器链,这个是核心了
public class HandlerExecutionChain {
private final Object handler;
private List<HandlerInterceptor> interceptorList = new ArrayList<>();
private int interceptorIndex = -1;
public HandlerExecutionChain(Object handler) {
this.handler = handler;
}
/**
* Add the given interceptor to the end of this chain.
*/
public void addInterceptor(HandlerInterceptor interceptor) {
interceptorList.add(interceptor);
}
/**
* Add the given interceptor at the specified index of this chain.
* @since 5.2
*/
public void addInterceptor(int index, HandlerInterceptor interceptor) {
interceptorList.add(index, interceptor);
}
public List<HandlerInterceptor> getInterceptors() {
return this.interceptorList;
}
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
public boolean applyPreHandle(HttpRequest request, HttpResponse response) throws Exception {
List<HandlerInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.size(); i++) {
HandlerInterceptor interceptor = interceptors.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
/**
* Apply postHandle methods of registered interceptors.
*/
public void applyPostHandle(HttpRequest request, HttpResponse response, Object obj) throws Exception {
List<HandlerInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
for (int i = interceptors.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors.get(i);
interceptor.postHandle(request, response, this.handler, obj);
}
}
}
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
public void triggerAfterCompletion(HttpRequest request, HttpResponse response, Exception ex) throws Exception {
List<HandlerInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
System.out.println("HandlerInterceptor.afterCompletion threw exception" + ex2.getMessage());
}
}
}
}
}
public class HandlerMethod {
private final Object bean;
private final Class<?> beanType;
private final Method method;
private final Object[] arguments;
public HandlerMethod(Object bean, Class<?> beanType, Method method, Object[] arguments) {
this.bean = bean;
this.beanType = beanType;
this.method = method;
this.arguments = arguments;
}
public Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(method);
try {
return method.invoke(bean, args);
}catch (Exception e){
System.out.println(e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
}
测试
public class DemoService {
public String test(){
return "11111111111111111111";
}
}
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpRequest request, HttpResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor 前置");
return true;
}
@Override
public void postHandle(HttpRequest request, HttpResponse response, Object handler, Object obj) throws Exception {
System.out.println("FirstInterceptor 处理中");
}
@Override
public void afterCompletion(HttpRequest request, HttpResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor 后置");
}
}
public class SecondInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpRequest request, HttpResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor 前置");
return true;
}
@Override
public void postHandle(HttpRequest request, HttpResponse response, Object handler, Object obj) throws Exception {
System.out.println("SecondInterceptor 处理中");
}
@Override
public void afterCompletion(HttpRequest request, HttpResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor 后置");
}
}
public class InterceptorTest {
public static void main(String[] args) throws Exception {
InterceptorRegistry registry = new InterceptorRegistry();
registry.addInterceptor(new FirstInterceptor())
.addIncludeConditions("aaa")
.addExcludeConditions("bbb")
.order(1);
registry.addInterceptor(new SecondInterceptor())
.addIncludeConditions("aaa")
.addExcludeConditions("ddd")
.order(2);
List<Object> interceptors = registry.getInterceptors();
dispatcher((List<HandlerInterceptor>)(List)interceptors);
}
private static void dispatcher(List<HandlerInterceptor> interceptors) throws Exception {
HandlerMethod handlerMethod = new HandlerMethod(new DemoService(), DemoService.class, DemoService.class.getMethod("test", null), null);
HandlerExecutionChain chain = new HandlerExecutionChain(handlerMethod);
for (HandlerInterceptor interceptor : interceptors) {
if (interceptor instanceof MappedInterceptor){
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches("aaa")) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else{
chain.addInterceptor(interceptor);
}
}
HttpRequest request = new HttpRequest();
HttpResponse response = new HttpResponse();
Exception exception = null;
try {
final boolean b = chain.applyPreHandle(request, response);
if (!b){
return;
}
// invoke 原方法
Object o = handlerMethod.doInvoke(null);
System.out.println(o);
chain.applyPostHandle(request, response, o);
}catch (Exception e){
exception = e;
System.out.println(e.getMessage());
}
chain.triggerAfterCompletion(request, response, exception);
}
}
输出结果
FirstInterceptor 前置
SecondInterceptor 前置
11111111111111111111
SecondInterceptor 处理中
FirstInterceptor 处理中
SecondInterceptor 后置
FirstInterceptor 后置
你可以修改拦截器的顺序或者修改拦截器的生效条件去测试,还有你也可以将某个拦截器的 preHandle 方法返回 false 去查看测试结果
欢迎在评论区留下你的总结