【SpringMVC框架】前端控制器源代码分析

来源:互联网 发布:装修平面图设计软件 编辑:程序博客网 时间:2024/05/16 08:29
前端控制器源代码分析

虽然前面讲了一些springmvc的入门程序和配置文件中映射器和适配器的配置,但是我们作为编程人员,了解框架的部分源码还是有必要的,比如前端控制器,它是如何通过Servlet的web.xml配置文件实现拦截并跳转至DispatcherServlet的呢?下面我们详细探讨

众多周知我们的入门程序的web.xml是这么配置的
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><!-- SpringMvc前端控制器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器,适配器等) 如果不配置contextConfigLoaction,默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml)--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 第一种:*.action。访问以.action结尾由DispatcherServlet进行解析; 第二种:/,所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析, 我们要配置不让DispatcherServlet进行解析。使用此种方法可以实现RESTful风格的url; 第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由 DispatcherServlet进行解析jsp地址,它不能根据jsp页面找到Handler,会报错--><url-pattern>*.action</url-pattern></servlet-mapping>  <welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list></web-app>

还记不记得springmvc的执行过程:

图-1.c.springmvc框架



通过前端控制器源码分析springmvc的执行过程。

我们点开org.springframework.web.servlet.DispatcherServlet看看,里面有一个doDiapatch的方法:
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);}}}

我们来分析这个方法
第一步:前端控制器接收请求

.action类型的URL通过过滤器进入DispatcherServlet类,调用其doDiapatch()方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);                ......}


第二步:前端控制器调用处理器映射器查找 Handler
在doDiapatch()方法中调用了DispatcherServlet类的getHandler方法
HandlerExecutionChain mappedHandler = null;......mappedHandler = getHandler(processedRequest, false);
其中getHandler方法:
@Deprecatedprotected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {return getHandler(request);}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 handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;}

说明映射器根据request当中的URL,找到了Handler,最终返回一个执行器的链(HandlerExecutionChain)。这个链里面有Handler。

第三步:调用处理器适配器执行Handler,得到执行结果ModelAndView
ModelAndView mv = null;......mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

第四步:视图渲染,将model数据填充到request域。

视图解析,得到view:
在doDiapatch()方法中有这一句
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

其中processDispatchResult方法
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 forwardreturn;}if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}}

其中render(mv, request, response);方法中有
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);

渲染方法:
view.render(mv.getModelInternal(), request, response);

调用view的渲染方法,将model数据填充到request域
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {//遍历model里面的数据,填充到request域for (Map.Entry<String, Object> entry : model.entrySet()) {String modelName = entry.getKey();Object modelValue = entry.getValue();if (modelValue != null) {request.setAttribute(modelName, modelValue);if (logger.isDebugEnabled()) {logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +"] to request in view with name '" + getBeanName() + "'");}}else {request.removeAttribute(modelName);if (logger.isDebugEnabled()) {logger.debug("Removed model object '" + modelName +"' from request in view with name '" + getBeanName() + "'");}}}}

大致了解了源码,便于更好的理解框架。
转载请注明出处:http://blog.csdn.net/acmman/article/details/46980497
1 0
原创粉丝点击