springmvc(1)DispatcherServlet源码简单解析
springmvc的简单配置
1.首先需要在web.xml中配置DispatcherServlet,这个类是springmvc的核心类,所以的操作都是由这里开始,并且大部分都是在这里面实现的,比如各种视图的解析,视图的
映射等等。配置文件:
- <servlet>
- <servlet-name>springServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup></load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springServlet</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
既然是和spring一套的,那肯定是有配置文件的,但是我们却没有配置文件路径,文件的默认路径是可以修改的,如果我们的这个文件没有配置路径的话,默认的路径是
- /WEB-INF/springServlet-servlet.xml // 默认的路径就是:/WEB-INF/[servlet的名称]-servlet.xml
但是我们是可以自己设置属性的,除了文件路径,还可以设置一下的几个属性:
- contextClass:实现WebApplicationContext接口的类,当前的servlet用它来创建上下文。如果这个参数没有指定, 默认使用XmlWebApplicationContext。
- contextConfigLocation:传给上下文实例(由contextClass指定)的字符串,用来指定上下文的位置。这个字符串可以被分成多个字符串(使用逗号作为分隔符) 来支持多个上下文(在多上下文的情况下,如果同一个bean被定义两次,后面一个优先)。
- namespace:WebApplicationContext命名空间。默认值是[server-name]-servlet。
文件既可以放在WEB-INF下面,也可以放在classpath下面,比如:
- <servlet>
- <servlet-name>springServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:springmvc.xml</param-value>
- </init-param>
- <load-on-startup></load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springServlet</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
注意一点的是,这个classpath指的是编译后的位置,刚开始学习框架的时候,总会犯这样的错误,找不到配置文件,就是因为classpath的问题。
对于web项目,还有一种通用的写法,就是放在ContextLoaderListener下面:
restful风格的
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath*:/spring-context*.xml</param-value>
- </context-param>
支持多文件的:
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:spring-common-config.xml,
- classpath:spring-budget-config.xml
- </param-value>
- </context-param>
这样子,springmvc基本上是配置好了,这里没有讲spring的配置。
上面配置好了简单的web.xml以后,我们来讲一下DispatcherServlet.
从上面我们应该就明白了,其实它就是一个servlet,既然是servlet,那么理解起来就简单多了。
DispathcherServlet最主要的就是下面几个方法,下面一一来简单看看:
- /**
- * Initialize the strategy objects that this servlet uses.
- * <p>May be overridden in subclasses in order to initialize further strategy objects.
- */
- protected void initStrategies(ApplicationContext context) {
- initMultipartResolver(context);
- initLocaleResolver(context);
- initThemeResolver(context);
- initHandlerMappings(context);
- initHandlerAdapters(context);
- initHandlerExceptionResolvers(context);
- initRequestToViewNameTranslator(context);
- initViewResolvers(context);
- initFlashMapManager(context);
- }
这个方法是初始化各种解析器,适配等等的方法,这个方法是在其父类的初始化方法中调用的,没记错的话,其实就是相当于Servlet的init方法执行时调用。首先一起了解下上面每一个方法初始化的都是什么:
- 1.MultipartResolver指的是文件上传解析类,对于文件上传的时候,需要使用到,我们看他的方法:
- private void initMultipartResolver(ApplicationContext context) {
- try {
//这里获取bean 注意这个常量在前面的是定义的:MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
//所以我们配置的时候 bean的名称必须是上面的这个 不然是不能识别的哦 注意咯- this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
- if (logger.isDebugEnabled()) {
- logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
- }
- }
- catch (NoSuchBeanDefinitionException ex) {
- // Default is no multipart resolver.
- this.multipartResolver = null;
- if (logger.isDebugEnabled()) {
- logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
- "': no multipart request handling provided");
- }
- }
- }
如果没有配置 那么默认就是没有文件上传解析的。这个时候,如果上传,那么会出一些问题的。
2.LocaleResolver这个是本地化解析,也就是做国际化的,如果没有设置,那么会默认为我们设置一个
3.ThemeResolver 看名字也知道,就是风格和主题解析类,默认也会有为我们设置一个
4.HandlerMappings :请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;从下面的代码中可以看出
- protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器对象);
//如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器,注意这里处理器值得是handler,而不是handlerMapping,形象的将
//就是handlerMapping是一个模板,处理器handler就是根据你的bean刻出的成型产品。- 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;
- }
5.HandlerAdapters:看到适配器了吧,对各种处理器包装成适配器,这样就能支持多种类型的处理器了。
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//将处理器进行包装,后面的操作都是都是由适配器进行工作
6HandlerExceptionResolvers:一场解析器,就比如出现错误的时候,可能统一调到某一个页面。默认也有实现,这个需求有太多中解决方案了,没什么好讲
7.RequestToViewNameTranslator:当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名;
8ViewResolvers:视图解析器。我们的配置中都会一般都会配置一个视图,就像这样:
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="suffix" value=".jsp"></property>
- <property name="prefix" value="/WEB-INF/views/module/"></property>
- </bean>
视图解析器就是将上面的进行解析。超类只有一个方法
- View resolveViewName(String viewName, Locale locale) throws Exception;
- 9.FlashMapManager值得是redirect的时候保存数据的一个相当于map分装的一个容器吧,但是官方是说在程序中一般不会使用的,比如在controller,就经常是用RedirectAttributes 来传输数据
讲完了几个比较重要的属性,然后将主要的几个放大,既然是servlet,那么我们就来看看service方法吧,这里的service是这样的:
- protected void doService(HttpServletRequest request, HttpServletResponse response)
里面有一个这样的依据代码需要引起重视,其他的代码都是配置一些属性什么的
- try {
- doDispatch(request, response);
- }
这个方法其实就是DispatchServlet的核心,我们前面讲到的解析器,适配器等等都是在这里操作的:
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;//前面讲过。handlerMapping映射成功,都会返回这个东西,其中包括处理器和拦截器- boolean multipartRequestParsed = false;
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- try {
- ModelAndView mv = null;
- Exception dispatchException = null;
- try {
//查看请求是否是Multipart(如文件上传)- processedRequest = checkMultipart(request);
- multipartRequestParsed = (processedRequest != request);
- // Determine handler for the current request.
//映射- mappedHandler = getHandler(processedRequest);
- 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()) {
- logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
- }
- 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(request, mv);
- mappedHandler.applyPostHandle(processedRequest, response, mv);
- }
- catch (Exception ex) {
- dispatchException = ex;
- }
//解析视图 最终会调用view.render(mv.getModelInternal(), request, response);将model传进去- 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
- if (mappedHandler != null) {
- mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
- }
- }
- else {
- // Clean up any resources used by a multipart request.
- if (multipartRequestParsed) {
- cleanupMultipart(processedRequest);
- }
- }
- }
- }
上面也就简单的了解了一下springmvc的入口,接下来几天在研究一下springmvc其他的一些功能。好多东西都是自己理解的,不知道对不对==。
springmvc(1)DispatcherServlet源码简单解析的更多相关文章
- springmvc(2)Controller源码简单解析
前面简单的分析了一下DispatcherServlet,接下来分析一下Controller,在web的MVC中,Controller就是其中的C,启动的一些页面逻辑处理,页面映射的功能: 首先看看超类 ...
- node-pre-gyp以及node-gyp的源码简单解析(以安装sqlite3为例)
title: node-pre-gyp以及node-gyp的源码简单解析(以安装sqlite3为例) date: 2020-11-27 tags: node native sqlite3 前言 简单来 ...
- Okhttp源码简单解析(一)
业余时间把源码clone下来大致溜了一遍,并且也参阅了其余大神的博客,在这里把自己的心得记录下来共享之,如有不当的地方欢迎批评指正.本文是Okttp源码解析系列的第一篇,不会深入写太多的东西,本篇只是 ...
- ForkJoinPool源码简单解析
ForkJoin框架之ForkJoinTask java 阅读约 62 分钟 前言 在前面的文章"CompletableFuture和响应式编程"中提到了ForkJoinTas ...
- StringBudiler源码简单解析
StringBudiler源码 继承关系树 底层实现 默认容量() 特别的添加方法(append) 1.继承关系树 继承自AbstractStringBuilder与StringBuffer同族 2. ...
- springmvc的DispatcherServlet源码——doDispatch方法解析
DispatcherServlet的doDispatch方法主要用作职责调度工作,本身主要用于控制流程,主要职责如下: 1.文件上传解析,如果请求类型是multipart将通过MultipartRes ...
- 源码深度解析SpringMvc请求运行机制(转)
源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请 ...
- SpringMVC 源码深度解析<context:component-scan>(扫描和注冊的注解Bean)
我们在SpringMVC开发项目中,有的用注解和XML配置Bean,这两种都各有自己的优势,数据源配置比較经经常使用XML配置.控制层依赖的service比較经经常使用注解等(在部署时比較不会改变的) ...
- FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
随机推荐
- 230行实现一个简单的MVVM
作者:mirone链接:https://zhuanlan.zhihu.com/p/24451202来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. MVVM这两年在前端届 ...
- 基础才是重中之重~ConcurrentDictionary让你的多线程代码更优美
回到目录 ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一起被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单 ...
- JS原生第一篇 (帅哥)
"流程控制语句":if.for. 1.1 if 选择语句,给程序添加了多种执行路线. 1 if(){ 2 语句1 3 }else if(){ 4 语句2 5 }else if( ...
- ObjectOutputStream和ObjectInputStream
官方解释: ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream.可以使用 ObjectInputStream 读取(重构)对象.通过使用流中的文 ...
- poj1273Drainage Ditches
#include<iostream> /* 题意:就是寻找从源点到汇点的最大流! 要注意的是每两个点的流量可能有多个,也就是说有重边,所以要把两个点的所有的流量都加起来 就是这两个点之间的 ...
- uva 10801 - Lift Hopping(最短路Dijkstra)
/* 题目大意: 就是一幢大厦中有0-99的楼层, 然后有1-5个电梯!每个电梯有一定的上升或下降速度和楼层的停止的位置! 问从第0层楼到第k层最少经过多长时间到达! 思路:明显的Dijkstra , ...
- Shell最多可以输入多少个参数?
在脚本编写过程中,通常会涉及到参数的输入.譬如,sh 1.sh 10 20,在执行1.sh这个脚本中,10即为第一个参数,20即为第二个参数.有时,就会有这个疑惑,即shell脚本最多可以支持多少个变 ...
- selenium处理select标签的下拉框
有时候我们会碰到<select></select>标签的下拉框.直接点击下拉框中的选项不一定可行.Selenium专门提供了Select类来处理下拉框. <select ...
- Docker - Docker国内镜像的配置及使用
Docker国内镜像 DaoCloud - Docker加速器 阿里云 - 开发者平台 微镜像 - 希云cSphere 镜像广场 - 时速云 灵雀云 网易蜂巢 阿里云的Docker加速器 阿里云 - ...
- 在Spring Boot中使用Https
本文介绍如何在Spring Boot中,使用Https提供服务,并将Http请求自动重定向到Https. Https证书 巧妇难为无米之炊,开始的开始,要先取得Https证书.你可以向证书机构申请证书 ...