SpringMVC中的责任链模式详解
本文以
SpringMVC
源码为依据来学习设计模式之责任链模式在框架中的落地。
背景
使用过
SpringMVC
都知道SpringMVC
中有一个在请求到达handler
也就是你的controller
里面的处理方法之前都会首先进入拦截器执行拦截器处理。实现HandlerInterceptor
接口的类可配置在MVC
中成为拦截器,统一拦截请求进行处理。
展示相关拦截器和配置的代码,方便理解。
拦截器DemoHandlerInterceptor.java
@Slf4j
public class DemoHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion...");
}
}
mvc
配置WebMVCConfig.java
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
// 注入用于测试的自定义拦截器
@Bean
public DemoHandlerInterceptor demoHandlerInterceptor(){
return new DemoHandlerInterceptor();
}
// 为springmvc添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(demoHandlerInterceptor());
}
}
SpringMVC中相关源码介绍
SpringMVC
中请求最终会被接收到DispatcherServlet
中进行处理,DispatcherServlet
作为请求分发和处理中心,可以理解为领导级人物。请求来到doDispatch()
方法中,进行映射和处理。
doDispathch()
源码如下所示:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
这里对请求处理的过程进行简要概括。我们提取源码中关于获取请求处理器、执行拦截器、执行处理器的代码。
重要代码如下所示:
// 获取处理器
//注意这里的类型时HandlerExecutionChain,这将是本文的重头戏
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
// 确定当前请求的处理程序适配器。
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 执行过滤器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行真正的处理器 也就是你在controller中写的处理方法
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 执行过滤器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
如果你背过DispatcherServlet
的执行原理相关的面试题对上面这段代码应该是比较好理解的了。这就是mvc的执行过程。这里面执行拦截器的实现的涉及思路就是责任链模式。从他对类的起名也不难看出这一点接下来就解析一下,过滤器HandlerExecutionChain
的相关内容。
拦截器执行链:HandlerExecutionChain
HandlerExecutionChain
在请求获取执行器的过程中被创建,也就是getHandler()
的过程中,内部调用模板类AbstractHandlerMapping
的getHandlerExecutionChain
方法从容器中寻找到SpringMVC
的拦截器并将这些拦截器放到HandlerExecutionChain
执行链中。关键代码如下所示:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
获取到这些拦截器之后,会在执行完成业务代码的前后执行HandlerExecutionChain
拦截器执行链的applyPreHandle
方法和applyPostHandle
方法。DispatcherServlet
的相关源码如下所示:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行所有拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行真正的handle业务代码
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 执行所有拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
这样就完成了整个拦截器责任链的实现。