上图表示当客户请求来到时,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. 「HNOI 2013」数列

    题目链接 戳我 \(Solution\) 这道题貌似并不难的样子\(QAQ\) 我们发现这个因为有首项的关系所以有点不太好弄.所以我们要将这个首项对答案的影响给去掉. 我们可以构建一个差分数组,我们令 ...

  2. luoguP2479 [SDOI2010]捉迷藏

    https://www.luogu.org/problemnew/show/P2479 据说可以用线段树做但是我不会,只能写一个 KD-Tree 了 对于每个点求出距离它最远的点和最近的点的距离,然后 ...

  3. React-Native 工程添加推送功能 (iOS 篇)

    推送已经是是手机应用的基本功能,如果自己实现一套推送系统费时费力,所有一般我们会使用第三方的推送服务,这里我使用「极光推送」作为集成推送的例子,因为有现成的 react native 插件 jpush ...

  4. UIViewController读书笔记

    当一个VC把另一个VC作为子view加到自己的view时,一定要先调用addChildViewController(_:)方法. 因为一个VC的root view,也就是VC的view只能被这个VC持 ...

  5. python2与python3差异,以及如何写两者兼容代码

    1.路径差异: 绝对导入:跳过包内,直接搜索 sys.path ,在sys.path的基础上进行我们的模块搜索. 相对导入:先包内,再包外,再,,, python2是默认相对导入的,因此对于一般性的导 ...

  6. 吃奶酪 状压dp

    题目描述 房间里放着n块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处. 输入输出格式 输入格式: 第一行一个数n (n<=15) 接下来每行2个实数,表示第i块 ...

  7. Python爬取LOL英雄皮肤

    Python爬取LOL英雄皮肤 Python 爬虫  一 实现分析 在官网上找到英雄皮肤的真实链接,查看多个后发现前缀相同,后面对应为英雄的ID和皮肤的ID,皮肤的ID从00开始顺序递增,而英雄ID跟 ...

  8. Angular material mat-icon 资源参考_Warning

    ul,li>ol { margin-bottom: 0 } dt { font-weight: 700 } dd { margin: 0 1.5em 1.5em } img { height: ...

  9. iOS开发ApplePay的介绍与实现

    1.Apple Pay的介绍 Apple Pay官方 1.1 Apple Pay概念 Apple Pay,简单来说, 就是一种移动支付方式.通过Touch ID/ Passcode,用户可使用存储在i ...

  10. jmeter安装部署、maven路径配置

    jmeter下载地址: https://jmeter.apache.org/download_jmeter.cgi 解压文件 配置jmeter环境变量 (1)设置jmeter解压目录的JMETER_H ...