springmvc处理请求源码
2020-09-11 本文已影响0人
sunpy
springmvc处理请求.jpg
1. FrameworkServlet抽象类设计
DispatcherServlet继承抽象类FrameworkServlet,最终父类为HttpServlet,本质上还是Servlet来处理请求。
代码结构设计思路:实现处理请求的doGet方法,其中doGet方法共性的流程都是doGet方法委派给processRequest方法,processRequest方法委派给doService方法。而doService是抽象方法,由继承FrameworkServlet的个性子类来实现doService的个性化内容方法(模板方法模式)。
// 处理请求,将请求委派给processRequest和doService
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
// 处理请求
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, startTime, failureCause);
}
}
2.DispatcherServlet处理请求入口(doService方法)
如果后面需要处理国际化和一些主题样式等,先在向后传的reuqest请求中,设置themeResolver主题样式解析器和localeResolver国际化解析器等属性。主要还是将请求委派到doDispatch方法去实现。
// 确定请求request的一些属性并且委派给doDispatch方法处理请求
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + requestUri + "]");
}
// 保留请求属性的快照,将当前的属性遍历保存到attributesSnapshot
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 确保框架对象对于处理器和视图对象可用
// 请求中保存一些主题属性和国际化解析器属性等
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// 还原请求的属性快照
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
3. doDispatch方法核心处理:处理请求,派发到不同的handler处理器
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.
// 1 根据请求获取对应处理器映射HandlerMapping
// 返回执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2 获取处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3 请求是否发生修改,未修改采取本地缓存
// 获取请求方法
String method = request.getMethod();
// 判断请求是否为GET请求
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
// 获取最后修改时间
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
// 如果请求没有修改,那么通知其使用本地缓存
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// 4 真正调用处理请求程序,返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
// 重置为默认的视图名称
applyDefaultViewName(request, mv);
// 调用已注册拦截器的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 5 ViewResolver解析视图
// 调用render方法渲染物理视图View
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
说明,粗略地分为5个步骤:
① 根据请求获取对应处理器映射HandlerMapping,返回执行链
② 获取处理器适配器
③ 请求是否发生修改,未修改直接返回,采取本地缓存
④ 真正调用处理请求程序,返回ModelAndView
⑤ ViewResolver解析视图,渲染物理视图View
-
① 根据请求获取对应处理器映射HandlerMapping,返回执行链(getHandler方法)
RequestMappingHandlerMapping类继承自祖先AbstractHandlerMapping抽象类,由祖先抽象类实现getHandler方法。
// 获取请求对应的HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
// 获取请求对应的HandlerExecutionChain处理器执行链
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
// 获取请求对应的HandlerExecutionChain处理器执行链
// 如果不存在,那么返回特定的处理器执行链
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求获取处理器执行链
Object handler = getHandlerInternal(request);
// 获取默认的处理器
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 封装处理器为处理器执行链并返回
return getHandlerExecutionChain(handler, request);
}
-
② getHandlerAdapter方法:获取处理器适配器
// 获取handler处理器对应的HandlerAdapter适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
// 判断HandlerAdapter是否支持handler处理器
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
- ③ 请求是否发生修改,未修改直接返回,采取本地缓存
通过ETAG和lastmodifiedtime来确定是否修改了请求资源,如果未修改就返回304状态码。
使用本地缓存的原理(看完就比较清楚为啥这么写了):https://www.jianshu.com/p/699d845a2a73
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
// 获取最后修改时间
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
// 如果请求没有修改,那么通知其使用本地缓存
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 检查是否修改过请求,通过ETAG确定资源,lastmodifiedtime来确定修改时间
@Override
public boolean checkNotModified(long lastModifiedTimestamp) {
if (lastModifiedTimestamp >= 0 && !this.notModified &&
(this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) {
long ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE);
this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
if (this.response != null) {
if (this.notModified && METHOD_GET.equals(getRequest().getMethod())) {
this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
this.response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
}
}
}
return this.notModified;
}
- ④ 真正调用处理请求程序,返回ModelAndView
执行handle方法的类为RequestMappingHandlerAdapter,继承自AbstractHandlerMethodAdapter抽象类,父类定义的handle方法,将具体实现下沉到RequestMappingHandlerAdapter的handleInternal方法。
@Override
protected final ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 检查支持的方法和所需的会话,并应用给定的缓存秒数
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
// Uses configured default cacheSeconds setting.
checkAndPrepare(request, response, true);
}
// Session互斥锁
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
// 为视图解析做准备
return invokeHandleMethod(request, response, handlerMethod);
}
通过反射的方式调用请求的方法,譬如我们Controller定义的方法
// 在给定请求的上下文中解析其参数值后调用该方法。
public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取当前请求方法的参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(this.getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
// 反射方式,使用参数调用给定的方法
Object returnValue = invoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
- ⑤ viewResolver解析视图,将model填充到view
// 渲染视图
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
// 渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
// 渲染ModelAndView
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 解析请求中的国际化
Locale locale = this.localeResolver.resolveLocale(request);
// 设置到响应中
response.setLocale(locale);
View view;
if (mv.isReference()) {
// 解析视图名称
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException(
"Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
// 将model填充到view即可
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '"
+ getServletName() + "'", ex);
}
throw ex;
}
}
// 遍历视图解析器,将视图解析为物理视图
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}