转:http://blog.csdn.net/zhouyuqwert/article/details/6853730

下面类图将主要的类及方法抽离出来,以便查看方便,根据类的结构来说明整个请求是如何工作的

主要使用到的技术有Spring的IOC容器和Servlet。

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

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

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

  1. <servlet>
  2. <servlet-name>dispatch</servlet-name>
  3. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  4. <load-on-startup>1</load-on-startup>
  5. </servlet>
  6. <servlet-mapping>
  7. <servlet-name>dispatch</servlet-name>
  8. <url-pattern>*.htm</url-pattern>
  9. </servlet-mapping>
 <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>
  2. <servlet-name>dispatch</servlet-name>
  3. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  4. <init-param>
  5. <param-name>namespace</param-name>
  6. <param-value>classes/dispatch-servlet</param-value>
  7. </init-param>
  8. <load-on-startup>1</load-on-startup>
  9. </servlet>
<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)
  2. throws Exception {
  3. return ((Controller) handler).handleRequest(request, response);
  4. }
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { return ((Controller) handler).handleRequest(request, response);
}



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



下面是请求转发的部分

  1. /**
  2. * Render the internal resource given the specified model.
  3. * This includes setting the model as request attributes.
  4. */
  5. @Override
  6. protected void renderMergedOutputModel(
  7. Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
    throws Exception {
  8. // Determine which request handle to expose to the RequestDispatcher.
  9. HttpServletRequest requestToExpose = getRequestToExpose(request);
  10. ...
  11. exposeModelAsRequestAttributes(model, requestToExpose);//这个方法看下面源码,request.setAttribute操作
  12. // Determine the path for the request dispatcher.
  13. String dispatcherPath = prepareForRendering(requestToExpose, response);
  14. ...
  15. // If already included or response already committed, perform include, else forward.
  16. if (useInclude(requestToExpose, response)) {
  17. ......
  18. }
  19. else {//重点看这部分,在根据请求以及配置文件获取到RequestDispatcher 对象之后,使用该对象做转发处理
  20. // Note: The forwarded resource is supposed to determine the content type itself.
  21. exposeForwardRequestAttributes(requestToExpose);
  22. if (logger.isDebugEnabled()) {
  23. logger.debug("Forwarding to resource [" + getUrl() +
    "] in InternalResourceView '" + getBeanName() +
    "'");
  24. }
  25. rd.forward(requestToExpose, response);
  26. }
  27. }
/**
* 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. /**
  2. * Expose the model objects in the given map as request attributes.
  3. * Names will be taken from the model Map.
  4. * This method is suitable for all resources reachable by {@link javax.servlet.RequestDispatcher}.
  5. * @param model Map of model objects to expose
  6. * @param request current HTTP request
  7. */
  8. protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request)
    throws Exception {
  9. for (Map.Entry<String, Object> entry : model.entrySet()) {
  10. String modelName = entry.getKey();
  11. Object modelValue = entry.getValue();
  12. if (modelValue !=
    null) {
  13. request.setAttribute(modelName, modelValue);
  14. if (logger.isDebugEnabled()) {
  15. logger.debug("Added model object '" + modelName +
    "' of type [" + modelValue.getClass().getName() +
  16. "] to request in view with name '" + getBeanName() +
    "'");
  17. }
  18. }
  19. else {
  20. request.removeAttribute(modelName);
  21. if (logger.isDebugEnabled()) {
  22. logger.debug("Removed model object '" + modelName +
  23. "' from request in view with name '" + getBeanName() +
    "'");
  24. }
  25. }
  26. }
  27. }
/**
* 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
  2. {
  3. private String greeting;
  4. public String getGreeting()
  5. {
  6. return greeting;
  7. }
  8. public void setGreeting(String greeting)
  9. {
  10. this.greeting = greeting;
  11. }
  12. public ModelAndView handleRequest(HttpServletRequest arg0,
  13. HttpServletResponse arg1) throws Exception
  14. {
  15. System.out.println(arg0.getRequestURI());//请求地址
  16. return new ModelAndView("home",
    "message", greeting);
  17. //返回一个视图资源对象,名为home,model为message的对象(即上面的exposeModelAsRequestAtrributes方法中使用的request.setAttribute
  18. }
  19. }
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使用。

  1. <bean
    name="/home.htm"
    class="com.iss.spring.web.HomeController">
  2. <property
    name="greeting"><value>Hello!This is Training!你好,这里是训练营!</value></property>
  3. </bean>
	<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. /**
  2. * Resolve the given view name into a View object (to be rendered).
  3. * <p>The default implementations asks all ViewResolvers of this dispatcher.
  4. * Can be overridden for custom resolution strategies, potentially based on
  5. * specific model attributes or request parameters.
  6. * @param viewName the name of the view to resolve
  7. * @param model the model to be passed to the view
  8. * @param locale the current locale
  9. * @param request current HTTP servlet request
  10. * @return the View object, or <code>null</code> if none found
  11. * @throws Exception if the view cannot be resolved
  12. * (typically in case of problems creating an actual View object)
  13. * @see ViewResolver#resolveViewName
  14. */
  15. protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
  16. HttpServletRequest request) throws Exception {
  17. for (ViewResolver viewResolver :
    this.viewResolvers) {
  18. View view = viewResolver.resolveViewName(viewName, locale);
  19. if (view != null) {
  20. return view;
  21. }
  22. }
  23. return null;
  24. }
/**
* 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">
  2. <property
    name="suffix"><value>.jsp</value></property>
  3. </bean>
<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>
  2. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  3. </listener>
  4. <context-param>
  5. <param-name>contextConfigLocation</param-name>
  6. <param-value>/WEB-INF/dispatch-data.xml,/WEB-INF/dispatch-service.xml</param-value>
  7. </context-param>
 <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";

Spring MVC中DispatcherServlet工作原理探究的更多相关文章

  1. spring mvc中DispatcherServlet如何得到ModelAndView的

    首先看下面这种张图,这张图说明了spring mvc整体的流程. 本文讲的就是如何从DispatcherServlet中得到ModerAndView的过程. 首先看DispatherServlet这个 ...

  2. Spring mvc中DispatcherServlet详解

    简介 DispatcherServlet是前端控制器设计模式的实现,提供SpringWebMVC的集中访问点,而且负责职责的分派,而且与spring IOC容器无缝集成,从而可以获得Spring的优势 ...

  3. Spring mvc 中 DispatcherServlet 的学习和理解

    上图表示当客户请求来到时,spring架构作出响应的流程,可以从图中看到看到请求分发的中心就是 DispatcherServlet 类,DispatcherServlet的任务是将请求发送给Sprin ...

  4. Spring Mvc中DispatcherServlet和Servlet的区别小结

    在web开发过程中开始接触的是servlet,用来处理用户请求.这几年随着spring 框架越来越成熟,几乎成了java web开发界的主流框架.既然这么受欢迎肯定有它的优点,spring框架在原来的 ...

  5. Spring MVC 中的基于注解的 Controller【转】

    原文地址:http://my.oschina.net/abian/blog/128028 终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 H ...

  6. Spring MVC中基于注解的 Controller

         终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响 ...

  7. Spring MVC中各个filter的用法

    转载:http://blog.csdn.net/qyp1314/article/details/42023725 Spring MVC中各个filter的用法 2014-12-19 09:08 105 ...

  8. Spring MVC中的HandlerMapping与HandlerAdapter

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  9. Spring MVC 中的基于注解的 Controller(转载)

           终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法 ...

随机推荐

  1. Big Data 應用:第二季(4~6月)台湾地区Game APP 变动分布趋势图

    图表简介: 该示意图表示了台湾地区第二季内所有Game APP类别的分布情形,经由该图表我们可以快速的了解到在这三个月内,哪类型的APP是很稳定:抑或者哪类型的APP是非常不稳定的. 名词解释: 类别 ...

  2. 删除mysql重复记录的办法

    网上有很多的办法,但是大多数都是通过临时表的办法,其实你是可以用一句简单的sql就可以做到: alter ignore table SOMETABLE add primary key(fields n ...

  3. Java写一个简单学生管理系统

    其实作为一名Java的程序猿,无论你是初学也好,大神也罢,学生管理系统一直都是一个非常好的例子,初学者主要是用数组.List等等来写出一个简易的学生管理系统,二.牛逼一点的大神则用数据库+swing来 ...

  4. C#当中的多线程_任务并行库(中)

    发现自己有点懒了!也可能是越往后越难了,看书理解起来有点费劲,所以这两天就每天更新一点学习笔记吧. 4.5 将APM模式转化为任务 书上提供的三种方式 方式一: class Program       ...

  5. CSS3高性能动画

    CSS动画属性会触发整个页面的重排relayout.重绘repaint.重组recomposite Paint通常是其中最花费性能的,尽可能避免使用触发paint的CSS动画属性,在CSS动画中使用w ...

  6. 使用Delphi读取网络上的文本文件,html文件

    使用Delphi读取网络上的txt和html文件 可以使用两种方法: 1.下载文件,然后进行读取 下载文件的Delphi代码可以参考: http://www.delphibbs.com/delphib ...

  7. ios专题 - Scrum

    什么是Scrum? Scrum是一个敏捷开发框架,是一个增量的.迭代的开发过程.在这个框架中,整个开发过程由若干个短的迭代周期组成,一个短的迭代周期称为一个 Sprint,每个Sprint的建议长度是 ...

  8. .NET中的委托——摘自MSDN

    封装一个方法,该方法只有一个参数并且不返回值. 命名空间:  System程序集:  mscorlib(在 mscorlib.dll 中) 语法   C#   public delegate void ...

  9. Function.prototype.apply()

    文章地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply ...

  10. 读书笔记之 - javascript 设计模式 - 观察者模式

    在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式是一种管理人与其任务(确切的讲,是对象及其行为和状态之间的关系)之间的关系的得力工具.用javascript的话来讲,这种模式的实 ...