1 DispatcherServlet
和其他web框架一样,Spring MVC也是围绕前端控制器模式设计,其中有一个中心Servlet,叫做DispatcherServlet,为请求处理提供一个 共享算法,实际的工作交给可配置的委托组件执行。这样的模式非常灵活,可以支持不同的工作流。
与任何Servlet一样,DispatcherServlet需要根据Servlet规范使用Java配置或在web.xml声明和映射。反过来,DispatcherServlet使用Spring配置为请求映射、视图解析、异常控制等找到需要的委托组件。
下面的Java配置示例注册并初始化DispatcherServlet, Servlet容器将自动检测DispatcherServlet。
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
除了使用Servlet API,还可以继承AbstractAnnotationConfigDispatcherServletInitializer并覆盖特定的方法
下面使用web.xml配置的方式注册和初始化DispatcherServlet.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Spring引导遵循不同的初始化顺序。Spring Boot没有挂接到Servlet容器的生命周期中,而是使用Spring配置来引导自身和嵌入的Servlet容器.过滤器和Servlet声明在Spring配置中检测到,并向Servlet容器注册。
1.1 上下文层级
DispatcherServlet需要WebApplicationContext(普通ApplicationContext的扩展)用于自己的配置。WebApplicationContext有一个指向ServletContext及其关联的Servlet的链接。它还绑定到ServletContext,以便应用程序可以使用requestcontext上的静态方法来查找WebApplicationContext(如果它们需要访问它)
于许多应用程序来说,拥有一个单一的WebApplicationContext就足够了。也可以有一个上下文层次结构,其中一个根WebApplicationContext在多个DispatcherServlet(或其他Servlet)实例之间共享,每个实例都有自己的子WebApplicationContext配置。
根WebApplicationContext通常包含基础设施bean,比如需要在多个Servlet实例之间共享的数据存储库和业务服务。这些bean可以有效地继承,并且可以在特定于Servlet的子WebApplicationContext中重写(即重新声明),该上下文通常包含给定Servlet的本地bean。下图显示了这种关系:
下面的示例配置WebApplicationContext层次结构
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/*" };
}
}
如果不需要应用程序上下文层次结构,则应用程序可以通过getRootConfigClasses()返回所有配置,并从getServletConfigClasses()返回null
下面展示作用效果相同的web.xml
<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>
1.2 特殊bean类型
DispatcherServlet委托特殊bean来处理请求并呈现适当的响应,这里所说的“特殊bean”是指实现框架约定的spring管理的对象实例。这些通常带有内置的约定,但是您可以自定义它们的属性并扩展或替换它们。
下表列出了DispatcherServlet检测到的特殊bean:
Bean 类型 | 解释 |
---|---|
HandlerMapping | 将请求和带有拦截器列表的处理器映射,用于预处理和后处理。映射基于一些标准,其细节因HandlerMapping实现而异。两个主要的HandlerMapping实现是RequestMappingHandlerMapping(它支持@RequestMapping注解的方法)和SimpleUrlHandlerMapping(它维护URI路径模式到处理程序的显式注册)。 |
HandlerAdapter | 帮助DispatcherServlet调用映射到请求的处理程序,而不管实际如何调用处理程序。例如,调用带注释的控制器需要解析注释。HandlerAdapter的主要目的是保护DispatcherServlet不受这些细节的影响。 |
HandlerExceptionResolver | 解决异常的策略,可能将异常映射到处理程序、HTML错误视图或其他目标。 |
ViewResolver | 将从处理程序返回的基于逻辑字符串的视图名称解析为要呈现给响应的实际视图 |
LocaleResolver, LocaleContextResolver | 解析客户端正在使用的语言环境和时区,以便能够提供国际化的视图 |
ThemeResolver | 解析web应用程序可以使用的主题——例如,提供个性化的布局 |
MultipartResolver | 在一些多部分解析库的帮助下解析多部分请求(例如,浏览器表单文件上传)的抽象。 |
FlashMapManager | 存储和检索输入和输出FlashMap,可用于将属性从一个请求传递到另一个请求,通常是通过重定向。 |