SpringMVC中的责任链模式详解

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()的过程中,内部调用模板类AbstractHandlerMappinggetHandlerExecutionChain方法从容器中寻找到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);

这样就完成了整个拦截器责任链的实现。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值