上图表示当客户请求来到时,spring架构作出响应的流程,可以从图中看到看到请求分发的中心就是 DispatcherServlet 类,DispatcherServlet的任务是将请求发送给Spring MVC控制器(controller) 。 控制器是一个用于处理请求的Spring组件。 在典型的应用程序中可能会有多个控制器, DispatcherServlet需要知道应该将请求发送给哪个控制器。 所以DispatcherServlet以会查询一个或多个处理器映射(handler mapping) 来确定请求的下一站在哪里。 处理器映射会根据请求所携带的URL信息来进行决策。

理解 DispatcherServlet 和 ContextLoadListener

DispatcherServlet 需要一个继承自ApplicationContext 的 WebApplicationContext 作为参数来配置自己。WebApplicationContext 是 ServletContext 和 Servlet 的关联者,对于很多应用,一个 WebApplicationContext 是足够并且可以充分发挥作用的,也有可能当我们有多个DispatcherServlet 并且想共享一下共同的bean 在这个应用中,这样我们可以定义一个root ApplicationContext里面包含所有的共同的bean 和

根WebApplicationContext (root WebApplicationContext )实际上已经包含了通常包含基础的beans ,例如数据存储(data repostitories )和需要被多个Servlet 实例共享的业务服务(business services)。这些beans可以被继承同时可以被重写(overridden)在 特定的Servlet中,或是在包含本地给定Servlet 的 child WebApplicationContext 中。而child WebApplicationContext  就是如下图的 Servlet WebApplicaitonContext .

以下引用参考文章中的解释

Spring's ApplicationContext provides the capability of loading multiple (hierarchical) contexts, allowing each to be focused on one particular layer, such as the web layer of an application or middle-tier services.

One of the canonical examples of using hierarchical ApplicationContext is when we have multiple DispatcherServlets in a web application and we're gonna share some of the common beans such as datasources between them. This way, we can define a root ApplicationContext that contain all the common beans and multiple WebApplicationContexts that inherit the common beans from the root context.

In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance

假如项目中只有一个DispatcherServlet , 那么我们可以把原来在 DispatcherServlet  的beans 全部移到父类Root WebApplicationContext中。

下面是一个实现了WebApplicationContext继承者的configuration。

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
} @Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { App1Config.class };
} @Override
protected String[] getServletMappings() {
return new String[] { "/app1/*" };
}
}

假如不需要 application context 是继承关系的(WebApplicationContext 和 child WebApplicationContext 的关系),那么可以返回所有的配置通过 getRootConfigClasses ( ) , getServletConfigClasses( )返回null 就行了。 

在Servlet 3.0环境中, 容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类, 如果能发现的话, 就会用它来配置Servlet容器。Spring提供了这个接口的实现, 名为SpringServletContainerInitializer, 这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。 Spring 3.2引入了一个便利的WebApplicationInitializer基础实现, 也就是AbstractAnnotationConfigDispatcherServletInitializer。 因为我们的 SpittrWebAppInitializer 扩展了AbstractAnnotationConfigDispatcherServletInitializer(同时也就实现了WebApplicationInitializer) , 因此当部署到Servlet 3.0容器中的时候, 容器会自动发现它, 并用它来配置Servlet上下文。(简单地说就是继承了AbstractAnnotationConfigDispatcherServletInitializer,就会形成一个child WebApplicationContext )

我们自己实现的MyWebAppInitializer 和下面用xml文件是同种效果的。

<web-app>

    <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param> <servlet>
<servlet-name>app1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app1-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>app1</servlet-name>
<url-pattern>/app1/*</url-pattern>
</servlet-mapping> </web-app>

同样,假如不需要 application context 是继承关系的(WebApplicationContext 和 child WebApplicationContext 的关系),那么可以返回所有的配置通过 “root context” , 而Servlet 中的参数 contextLocation 返回null 就行了。

实例理解DispatcherServlet

假如我使用Spring MVC, Spring Security 和Spring Data JPA 来构建我的应用,那么我需要知道三个 config files , WebConfig 包含了web 相关的配置, 例如 ViewResolvers , Controllers , ArgumentResolver ,代码如下:

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.so.web")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp"); return viewResolver;
} @Override
public void configurePathMatch(PathMatchConfigurer configurer) {
final boolean DO_NOT_USE_SUFFIX_PATTERN_MATCHING = false;
configurer.setUseSuffixPatternMatch(DO_NOT_USE_SUFFIX_PATTERN_MATCHING);
}
}

这里我们定义了一个ViewResolver , 同时我们需要一个RepositoryConfig 配置数据有关的类,例如 DataSource 和 TransactionManager 等等。

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.so.repository")
public class RepositoryConfig {
@Bean
public DataSource dataSource() { ... } @Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... } @Bean
public PlatformTransactionManager transactionManager() { ... } }

SecurityConfig 包含了安全相关的成员。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception { ... } @Override
protected void configure(HttpSecurity http) throws Exception { ... }
}

假如我们只有一个DispatcherServlet 下面我们有两种配置方法:

  1 public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
2 @Override
3 protected Class<?>[] getRootConfigClasses() {
4 return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class };
5 }
6
7 @Override
8 protected Class<?>[] getServletConfigClasses() {
9 return new Class<?>[] { WebConfig.class };
10 }
11
12 @Override
13 protected String[] getServletMappings() {
14 return new String[] { "/" };
15 }
16 }

或者是

  1 public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
2 @Override
3 protected Class<?>[] getRootConfigClasses() {
4 return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class, WebConfig.class };
5 }
6
7 @Override
8 protected Class<?>[] getServletConfigClasses() {
9 return null;
10 }
11
12 @Override
13 protected String[] getServletMappings() {
14 return new String[] { "/" };
15 }
16 }

ContextLoaderListener

引导监听Spring 的 root WebApplicationContext 的启动和关闭,在 Spring 3.1 中,ContextLoaderListener 支持通过 ContextLoaderListener(WebApplicationContext)来初始化 root WebApplicationContext .

特殊的bean

DispatcherServlet 委托给一些特殊的bean去处理请求和返回对应的响应,这些

DispatcherServlet

参考阅读

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和Servlet的区别小结

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

  4. Spring MVC中DispatcherServlet工作原理探究

    转:http://blog.csdn.net/zhouyuqwert/article/details/6853730 下面类图将主要的类及方法抽离出来,以便查看方便,根据类的结构来说明整个请求是如何工 ...

  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中的HandlerMapping与HandlerAdapter

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

  8. Servlet的生命周期以及在Spring MVC中调用流程

    接触Web时间比较久,虽然知道Servlet的生命周期但是理解却还是不够,今天刚好debug代码涉及这块就利用余下时间研究了一下. Servlet的生命周期以及处理浏览器请求的过程.Servlet接口 ...

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

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

随机推荐

  1. 24. 两两交换链表中的节点 leetcode

    题目: 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换. 示例: 给定 1->2->3->4, 你应该返回 ...

  2. php 多维数据根据某个或多个字段排序

    实现多维数组的指定多个字段排序 上面的实例讲解了如何实现多维数组指定一个字段排序,但如果要实现指定多个字段来对数组进行排序该如何思考? 多个字段是几个?2个,3个或更多,所以这个不确定的因素需要排除. ...

  3. AOP之 Filter实用

    前言 开心一笑~~~ 一个年轻的程序员和一个项目经理登上了一列在山里行驶的火车,他们发现列车上几乎都坐满了,只有两个在一起的空位,这个空位的对面是一个老奶奶和一个年轻漂亮的姑娘.两个上前坐了下来.程序 ...

  4. Xamarin Android Webview中JS调用App中的C#方法

    参考链接:https://github.com/xamarin/recipes/tree/master/Recipes/android/controls/webview/call_csharp_fro ...

  5. luoguP4755 Beautiful Pair

    https://www.luogu.org/problemnew/show/P4755 考虑分治,在 [l, r] 区间中用线段树找到最大的一个点,处理经过它的可行数对的个数,统计个数可以离线树状数组 ...

  6. php面向对象编程_2

    1, 抽象类 ,用abstract关键字来修饰一个类,这个类就是抽象类:如果用abstract关键字来修饰一个方法,这个方法就是抽象方法,如果是抽象方法就不能实现(即抽象方法只能声明,不能定义). 抽 ...

  7. iOS开发之像素Compositing

    假如Layer S·在Layer D上面,则最终的屏幕的颜色值如下: \[R = S + D \cdot (1- S_\alpha)\] \(R\): 最终的RGB \(S\): source col ...

  8. Machine learning吴恩达第二周coding作业(选做)

    1.Feature Normalization: 归一化的处理 function [X_norm, mu, sigma] = featureNormalize(X) %FEATURENORMALIZE ...

  9. (一)使用appium之前为什么要安装nodejs???

    很多人在刚接触appium自动化时,可能会像我一样,按照教程搭建好环境后,却不知道使用appium之前为什么要用到node.js,nodejs到底和appium是什么关系,对nodejs也不是很了解, ...

  10. git 修改配置

    git config 查看配置信息 config 配置项帮助信息 $ git config config 配置有system级别 global(用户级别) 和local(当前仓库)三个设置项 从sys ...