SpringMVC工作原理的示例分析

小编给大家分享一下Spring MVC工作原理的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

创新互联专注于企业营销型网站建设、网站重做改版、寿光网站定制设计、自适应品牌网站建设、H5响应式网站电子商务商城网站建设、集团公司官网建设、外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为寿光等各大城市提供网站开发制作服务。

应用示例

在讲工作原理之前,我们先看一个简单的spring mvc(ssm)示例,以及实现的效果

工程代码地址:ssm-web 

Spring MVC工作原理的示例分析

工程结构与效果如上所示,我们不做过多的探究,我们打起精神往下看本篇的重点

工作原理

准备 - 资源的加载与初始化

1、DispatcherServlet 静态初始化

DispatcherServlet中有如下静态块

static {
 // Load default strategy implementations from properties file.
 // This is currently strictly internal and not meant to be customized
 // by application developers.
 try {
  ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
  defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
 }
 catch (IOException ex) {
  throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
 }
 }

这里会将DispatcherServlet.properties中的内容读取到DispatcherServlet的属性:private static final Properties defaultStrategies中,DispatcherServlet.properties内容如下

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
 org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
 org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
 org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

指定了DispatcherServlet策略接口的默认实现,后续DispatcherServlet初始化策略的时候会用到

2、interceptor定义的加载

spring启动过程中会调用InterceptorsBeanDefinitionParser的parse方法来解析出我们自定义的interceptor定义,封装成MappedInterceptor类型的bean定义,并放到spring容器中;我们可以简单的认为spring容器中已经存在了我们自定义的interceptor的bean定义

3、DispatcherServlet初始化策略:initStrategies

DispatcherServlet的继承图如下

Spring MVC工作原理的示例分析

DispatcherServlet是一个Servlet,tomcat启动过程中会调用其init方法,一串的调用后,会调用DispatcherServlet的initStrategies方法

protected void initStrategies(ApplicationContext context) {
 initMultipartResolver(context);
 initLocaleResolver(context);
 initThemeResolver(context);
 initHandlerMappings(context);
 initHandlerAdapters(context);
 initHandlerExceptionResolvers(context);
 initRequestToViewNameTranslator(context);
 initViewResolvers(context);
 initFlashMapManager(context);
}

实例化步骤1中的默认实现,并填充到DispatcherServlet各个属性值中

4、DefaultAnnotationHandlerMapping的拦截器初始化

DispatcherServlet.properties种指定了两个默认的HandlerMapping:BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping,这两者的类继承图如下(我们暂时只关注DefaultAnnotationHandlerMapping)

Spring MVC工作原理的示例分析

DefaultAnnotationHandlerMapping间接实现了ApplicationContextAware,那么在DefaultAnnotationHandlerMapping实例初始化过程中,会调用setApplicationContext(ApplicationContext applicationContext)方法,一串调用后,会来到AbstractUrlHandlerMapping的initApplicationContext()

@Override
protected void initApplicationContext() throws BeansException {
 extendInterceptors(this.interceptors);
 detectMappedInterceptors(this.mappedInterceptors);
 initInterceptors();
}

初始化了DefaultAnnotationHandlerMapping的拦截器:interceptor

我们来看下具体的初始化过程,看看上面的顺序是否只是我个人的臆想?

Spring MVC工作原理的示例分析

可以看到,初始化顺序就是我们上面说的,不是我个人的意淫;此时的DefaultAnnotationHandlerMapping中有我们自定义的MyInterceptor。初始化过程我们需要关注的就是上述这些,下面我们一起看看具体请求的过程

请求的处理

请求从servlet的service开始,一路到DispatcherServlet的doDispatch,如下图

Spring MVC工作原理的示例分析

doDispatch

/**
 * Process the actual dispatching to the handler. 将请求分发到具体的handler,也就是我们的controller
 * 

The handler will be obtained by applying the servlet's HandlerMappings in order.  * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters  * to find the first that supports the handler class.  * 

All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers  * themselves to decide which methods are acceptable.  * @param request current HTTP request  * @param response current HTTP response  * @throws Exception in case of any kind of processing failure  */ 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. 决定哪个handler来处理当前的请求    // mappedHandler是由handler和interceptor集合组成的一个执行链,有点类似FilterChain    mappedHandler = getHandler(processedRequest);    if (mappedHandler == null || mappedHandler.getHandler() == null) {     noHandlerFound(processedRequest, response);     return;    }    // Determine handler adapter for the current request. 决定哪个adapter来处理当前的请求    // handlerMapping是找出适配的handler,而真正回调handler的是adapter    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;     }    }    // handler的前置处理,也就是调用适配当前url的interceptor的preHandler方法    if (!mappedHandler.applyPreHandle(processedRequest, response)) {     return;    }    try {     // Actually invoke the handler. 真正调用handler     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());    }    finally {     if (asyncManager.isConcurrentHandlingStarted()) {      return;     }    }    applyDefaultViewName(request, mv);    // handler的后置处理,也就是调用适配当前url的interceptor的postHandler方法    mappedHandler.applyPostHandle(processedRequest, response, mv);   }   catch (Exception ex) {    dispatchException = ex;   }   // 处理handler返回的结果,会调用适配当前url的interceptor的afterCompletion方法   // 这里会将响应结果返回给请求者   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);   }  } }

handlerMapping具体如何找到匹配当前url的handler(一般而言就是我们的controller)、handlerAdapter具体如何回调真正的handler,有兴趣的可以自行去跟下,我就不跟了。我们具体看下processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); 这个与我们最初的疑问有关

processDispatchResult

Spring MVC工作原理的示例分析

可以看到model中的persons会被设置到request的attributes中,然后转发请求到show_person.jsp,转发过程中request作用域的变量仍然有效,所以show_person.jsp中的jstl标签和el表达式能够取到persons变量,最后将show_person.jsp中的内容填充好之后的静态内容返回给请求者;至此就完成了一次请求的响应

问题解答

回到我们开篇的疑问:Spring mvc是何时、何地、如何将Model中的属性绑定到哪个作用域?想必大家已经知道答案了

Controller中的model、ModelMap的注入由spring mvc完成,这个不是请求传入的参数,用于绑定变量到Servlet作用域;默认情况下,在DispatcherServlet调用了真正的handler之后,将结果返回给请求者的过程中,将model、modelMap中的变量设置到了request的attributes中,转发的过程中,request中的变量仍然有效,所以show_person.jsp中能取到persons这个变量,自此疑问得到解答

总结

1、Spring MVC工作原理图

图是用的别人的,具体是谁的我也不记得了(捂脸)

Spring MVC工作原理的示例分析

以上是“Spring MVC工作原理的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!


名称栏目:SpringMVC工作原理的示例分析
本文来源:http://hbruida.cn/article/pcioje.html