文档章节

Spring DispatcherServlet与handlerinterceptor 的区别

Oscarfff
 Oscarfff
发布于 2015/05/28 11:30
字数 1802
阅读 82
收藏 0

3.1、DispatcherServlet作用

DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。 。

DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:

1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;

2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);

3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);

4、通过ViewResolver解析逻辑视图名到具体视图实现;

5、本地化解析;

6、渲染具体的视图等;

7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。

从以上我们可以看出DispatcherServlet主要负责流程的控制(而且在流程中的每个关键点都是很容易扩展的)。

3.1.1 DispatherServlet 继承类关系

假如我们要实现一个请求home.htm然后返回home.jsp视图资源则

当home.htm请求到达时,我们需要DispatcherServlet来处理该请求,所以首先配置该Servlet

第一步需要在web.xml中配置DispatcherServlet,使该servlet来接收请求并做进一步处理。

[html] view plaincopyprint?

  1. <servlet>  
        <servlet-name>dispatch</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>dispatch</servlet-name>  
        <url-pattern>*.htm</url-pattern>  
    </servlet-mapping>


这个部分很好理解,如果请求以.htm结尾则交给名为dispatch类为DispatcherServlet的Servlet处理。


从类图中很容易看出DispatcherServlet最终继承的是HttpServlet,也就是说它同样满足Servlet的工作原理

Servlet初始化时需要调用init方法,在HttpServletBean中实现,该init方法调用了initServletBean,该方法在FrameworkServlet中实现

initServletBean主要初始化关于配置文件的内容,比如{servlet-name}-servlet.xml


第二步,需要在/WebRoot/WEB-INF下新建名为{servlet-name}-servlet.xml的spring bean配置文件。(该示例中即为dispatch-servlet.xml)

在初始化过程中会去寻找该配置文件,当然我们也可以自己去设置参数来更改配置文件所在路径


比如我们如果在src下新建的该配置文件dispatch-servlet,在编译后会被复制到WEB-INF/classes文件夹下,

配置文件还是按照命名规范做吧(可以修改为其他名字)

  1. <servlet>  
            <servlet-name>dispatch</servlet-name>  
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
            <init-param>  
                <param-name>namespace</param-name>  
                <param-value>classes/dispatch-servlet</param-value>  
            </init-param>  
            <load-on-startup>1</load-on-startup>  
        </servlet>


此时的配置就会去寻找/WEB-INF/classes/dispatch-servlet.xml


当请求到达后Servlet将调用service方法进行处理,由于我们是通过输入网址方式的get方法请求,Servlet将调用doGet方法

此处的doGet方法在FrameworkServlet中实现,doGet方法调用processRequest方法,processRequest则调用doService方法处理

而doService在DispatcherServlet中实现,doService再调用了DispatcherServlet的doDispatch方法,

该方法则会根据request找到转发对象,并进行请求转发操作,

下面是获取实际的视图资源部分

  1. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
                throws Exception {  
      
            return ((Controller) handler).handleRequest(request, response);  
        }


这里需要我们自己实现Controller接口并实现handleRequest方法,返回对应的ModelAndView对象。


下面是请求转发的部分

  1. /** 
         * Render the internal resource given the specified model. 
         * This includes setting the model as request attributes. 
         */  
        @Override  
        protected void renderMergedOutputModel(  
                Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {  
      
            // Determine which request handle to expose to the RequestDispatcher.  
            HttpServletRequest requestToExpose = getRequestToExpose(request);  
      
            ...  
                     exposeModelAsRequestAttributes(model, requestToExpose);//这个方法看下面源码,request.setAttribute操作  
                      // Determine the path for the request dispatcher.  
            String dispatcherPath = prepareForRendering(requestToExpose, response);  
      
                ...  
      
            // If already included or response already committed, perform include, else forward.  
            if (useInclude(requestToExpose, response)) {  
                ......  
            }  
      
            else {//重点看这部分,在根据请求以及配置文件获取到RequestDispatcher 对象之后,使用该对象做转发处理  
                // Note: The forwarded resource is supposed to determine the content type itself.  
                exposeForwardRequestAttributes(requestToExpose);  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");  
                }  
                rd.forward(requestToExpose, response);  
            }  
        }

下面是设置model和modelValue

  1. /** 
         * Expose the model objects in the given map as request attributes. 
         * Names will be taken from the model Map. 
         * This method is suitable for all resources reachable by {@link javax.servlet.RequestDispatcher}. 
         * @param model Map of model objects to expose 
         * @param request current HTTP request 
         */  
        protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {  
            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() + "'");  
                    }  
                }  
            }  
        }

第三步,编写实现Controller的类

  1. public class HomeController implements Controller  
    {  
        private String greeting;  
      
        public String getGreeting()  
        {  
            return greeting;  
        }  
      
        public void setGreeting(String greeting)  
        {  
            this.greeting = greeting;  
        }  
      
        public ModelAndView handleRequest(HttpServletRequest arg0,  
                HttpServletResponse arg1) throws Exception  
        {  
            System.out.println(arg0.getRequestURI());//请求地址  
            return new ModelAndView("home", "message", greeting);  
    //返回一个视图资源对象,名为home,model为message的对象(即上面的exposeModelAsRequestAtrributes方法中使用的request.setAttribute  
        }  
      
    }


第四步,在dispatch-servlet.xml中配置该bean提供给spring web使用。

<bean name="/home.htm" class="com.iss.spring.web.HomeController">  
    <property name="greeting"><value>Hello!This is Training!你好,这里是训练营!</value></property>  
</bean>


这里name将用来匹配请求的资源(默认的使用BeanNameUrlHandlerMapping处理,由bean Name映射 URL),在home.htm请求到达时,

spring将使用实现了Controller接口的HomeController的handleRequest方法来返回映射的视图资源。


在得到MoldelAndView对象后,需要根据这个MoldelAndView对象得到View name然后来解析得到View对象

  1. /** 
         * Resolve the given view name into a View object (to be rendered). 
         * <p>The default implementations asks all ViewResolvers of this dispatcher. 
         * Can be overridden for custom resolution strategies, potentially based on 
         * specific model attributes or request parameters. 
         * @param viewName the name of the view to resolve 
         * @param model the model to be passed to the view 
         * @param locale the current locale 
         * @param request current HTTP servlet request 
         * @return the View object, or <code>null</code> if none found 
         * @throws Exception if the view cannot be resolved 
         * (typically in case of problems creating an actual View object) 
         * @see ViewResolver#resolveViewName 
         */  
        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;  
        }


此处需要我们配置viewResolver bean给spring使用,指明使用哪个类充当viewResolver并具有什么属性

第五步,配置viewResolver bean

  1. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <property name="suffix"><value>.jsp</value></property>  
        </bean>


中间可以加上prefix或者suffix

这些配置完成后,spring就会根据请求地址以及配置信息,找到视图资源并做请求转发操作


总结:整个流程分析下来,其实主要就是做两个操作,

首先请求信息到达DispatchServlet,Servlet中根据请求信息与配置文件找到映射的视图资源

然后使用RequestDispatch请求转发到该视图资源。

另外,可以分成多个bean配置文件,在web.xml中配置载入

  1. <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>  
    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>/WEB-INF/dispatch-data.xml,/WEB-INF/dispatch-service.xml</param-value>  
    </context-param>


其中contextConfigLocation这个名字可能是匹配FrameworkServlet的setContextConfigLocation方法

也有可能是匹配ContextLoaderListener继承ContextLoader的CONFIG_LOCATION_PARAM

public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
(不确定,不太了解context-param的用法,API上两个类关于这个变量的说明都类似,也分不太清楚,反正可以这么记- -||)


然后配置的viewResolver bean的id为什么要为viewResolver,下面的是DispatcherServlet中一个静态字符串说明了一切

public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

3.2 下面看看看处理请求的流程

图片上面的Frontcontroller 就相当于Dispatcherservlet


本文转载自:http://jinnianshilongnian.iteye.com/blog/1602617

Oscarfff
粉丝 73
博文 816
码字总数 97116
作品 0
崇明
后端工程师
私信 提问
springmvc java对象转json,上传下载,拦截器Interceptor以及源码解析

只是写一个<a href = "testJson">测试json</a> 然后再springmvc.xml中开启注解驱动mvc:annotation-driven/ 然后需要印如jackson的三个jar包,jackson是阿里巴巴产品,能够自动将java对象转为......

architect刘源源
06/20
111
0
SpringMVC开发 知识点速查

SpringMVC入门 什么是SpringMVC 实现MVC设计模式的框架 SpringMVC核心组件 DispatcherServlet 前置控制器,调度 Handler 处理器,完成具体业务逻辑 HandlerMapping 将请求映射到Handler,映射...

linxinzhe
2018/05/19
0
0
SpringMVC 拦截器实现原理和登录实现

SpringMVC 拦截器的原理图 springMVC拦截器的实现一般有两种方式 第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口 第二种方式是继承实现了HandlerInterceptor接口...

菜鸟腾飞
03/15
0
0
SpringMVC springMVC的拦截器

一、 拦截器的作用 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。 1.【拦截器链】(Intercep...

edison_kwok
04/30
15
0
第三章:DispatcherServlet详解

3.1、DispatcherServlet作用 DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有...

xiejunbo
2014/12/16
15
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
今天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
今天
6
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
今天
4
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
今天
2.5K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部