springmvc流程大致分析4 DispatcherServlet请求转发

来源:互联网 发布:拍动态图片软件 编辑:程序博客网 时间:2024/05/23 13:10
DispatcherServlet跟所有servlet一样都是通过service来接收客户端的请求,然后判断请求类型,然后进入对应的
doXxx方法的(这些方法在FrameworkServlet中被复写),以doGet方法为例:
protected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}

可以看到实际上处理doGet是在processRequest中被处理的,

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 = null;if (previousAttributes == null || (previousAttributes instanceof ServletRequestAttributes)) {requestAttributes = new ServletRequestAttributes(request);}initContextHolders(request, localeContext, requestAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), getRequestBindingInterceptor(request));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()) {if (logger.isDebugEnabled()) {logger.debug("Leaving response open for concurrent processing");}}else {this.logger.debug("Successfully completed request");}}}if (this.publishEvents) {// Whether or not we succeeded, publish an event.long processingTime = System.currentTimeMillis() - startTime;this.webApplicationContext.publishEvent(new ServletRequestHandledEvent(this,request.getRequestURI(), request.getRemoteAddr(),request.getMethod(), getServletConfig().getServletName(),WebUtils.getSessionId(request), getUsernameForRequest(request),processingTime, failureCause));}}}

processRequest的大致逻辑是:

以doService方法为界点,

之前的代码主要就是从request中取出当前的请求对象和属性分别设置到2个ThreadLocal对象中:
LocaleContextHolder和RequestContextHolder,也就是对象和属性都被绑定在当前请求线程上了。

之后的代码主要就是对LocaleContextHolder和RequestContextHolder的请求对象和属性进行解绑,
以及发布一个ServletRequestHandledEvent事件,可以通过注册监听器监听该事件。

可以看到processRequest方法其实也只是做了一些request参数的绑定和解绑,而真正处理请求的方法是doService,
doService是一个抽象方法,由DispatcherServlet重写
,代码如下:

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 + "]");}// Keep a snapshot of the request attributes in case of an include,// to be able to restore the original attributes after the include.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));}}}// Make framework objects available to handlers and view objects.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;}// Restore the original attribute snapshot, in case of an include.if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);}}}

DispatcherServlet的doService逻辑主要是将前面初始化的容器上下文,本地解析器等springmvc编程元素设置到
request中,供下一步使用,而真正完成请求转发是在doDispatch方法中被处理,它封装了springmvc处理请求转发的所有流程,其定义如下:

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, false);if (mappedHandler == null || mappedHandler.getHandler() == 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 = "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 {// Actually invoke the handler.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;}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 afterCompletionmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}

doDispatch方法逻辑大概是:

1.mappedHandler = getHandler(processedRequest, false);
遍历之前初始化HandlerMapping列表(handlerMappings,在onRefresh中初始化),返回第一个调用getHandler
不为空的对象,得到HandlerExecutionChain对象。

而HandlerMapping对象的getHandler方法传入HttpservletRequest参数,意味着HandlerMapping可以根据request
的任意信息来决定生成HandlerExecutionChain的策略,如请求头,url路径,cookie,session(最常用还是url路径)

这意味着,我们可以自己编写HandlerMapping实现类,自定义根据request的哪个信息来生成HandlerExecutionChain。

HandlerExecutionChain主要由

private final Object handler;
private HandlerInterceptor[] interceptors;
组成,

其中handler代表HandlerAdapter实际执行的处理对象,它被定义成Object的意义在于你可以将java中的任意对象定义成
Handler来执行,返回最后的视图。

而handler执行前后,HandlerInterceptor列表将被依次执行,它可以看做是最handler执行方法的环绕通知,用于对handler
执行方法进行方便的处理和扩展,拦截器一般是自定义的。

2.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
遍历之前初始化的HandlerAdapter列表(handlerAdapters),返回第一个supports方法为true的对象,
得到HandlerAdapter对象。

我们也可以通过自定义的HandlerAdapter来执行handler对象。

3.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
HandlerAdapter对象调用handle方法,返回ModelAndview对象。

ModelAndview是springmvc中视图和模型数据的聚合,而视图则抽象成View接口了。
View接口定义了一个render方法用于渲染视图。其实现类包含在HandlerAdapter对象执行handle方法的返回值
中(ModelAndview),而返回的ModelAndview到View有一个视图解析的过程,所以返回的ModelAndview即可以
包含真正的视图View,也可以仅仅包含视图名,springmvc的视图解析器负责将视图名转成真正的视图对象。


至此,springmvc的请求处理流程结束。

0 0
原创粉丝点击