前言
实际上我们的001-Spring Boot HelloWorld就是Spring boot实现的springMVC Helloworld代码。
DispatcherServlet
Spring MVC中所有的请求都有DispatcherServlet来负责分发处理。当然需要很多相关的组件。
java配置方式注册DispatcherServlet
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
web.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/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>
</web-app>
以上两种方式是在不使用Spring boot时的注册方式。
使用Spring boot的方式
其实我们的Spring Boot HelloWorld一章就是使用的该方式,Spring Boot 遵循不同的初始化顺序。Spring Boot 没有钩入 Servlet 容器的生命周期,而是使用 Spring 配置来引导自身和嵌入式 Servlet 容器。
相关组件
在org.springframework.web.servlet.DispatcherServlet源码中有如下初始化方法
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
其分别注册了如下Spring MVC的相关组件,其中最重要的是HandlerMapping和HandlerAdapter
类 | 说明 |
HandlerMapping | HandlerMapping有多个实现,在DispatcherServlet也是以集合的形式存在,意味着同一个请求可能会有多个HandlerMapping来处理,我们的SpringMVC的拦截器也是通过HandlerMapping映射到处理逻辑的。RequestMappingHandlerMapping是最常用的一个实现,支持带@RequestMapping注释的方法。返回HandlerExecutionChain对象 |
HandlerAdapter | 处理请求逻辑,返回ModelAndView对象 |
LocaleResolver | 解析墙角客户端可能的时区,以便能提供国际化的视图。 |
ViewResolver | 视图解析器,将ModelAndView对象,解析为View对象。 |
MultipartResolver | 解析多不分请求(如:表单中的文件上传)等。 |
HandlerExceptionResolver | 异常解析器。 |
HandlerMapping
DispatcherServlet的initHandlerMappings(context);方法源码如下:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var4) {
}
}
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
Iterator var6 = this.handlerMappings.iterator();
while(var6.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var6.next();
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
spring boot在使用mvc的时候,默认注册了几个HandlerMapping注意顺序,源码中用了sort方法排序的。
HandlerMapping接口定义的方法如下
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
HandlerMapping返回了一个HandlerExecutionChain(执行器链)对象,该对象包含两个重要属性,一个是handler(Object类型)对象,一个是拦截器集合(List<HandlerInterceptor>)。
handler是Object类型,名义上他可以是任意类型,通过它我们可以确定到底用哪一个HandlerAdapter(处理适配器)RequestMappingHandler对应的handler对象是HandlerMethod。通过HandlerMethod我们可以找到对应的HandlerAdapter实际处理类。
在每个请求执行的时候会执行如下DispatcherServlet方法
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
DispatcherServlet通过当前的请求对象request遍历我们初始化的HandlerMapping集合,以获取对应的HandlerExecutionChain对象。
HandleAdapter
DispatcherServlet的initHandlerAdapters(context);方法源码如下:
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
Spring boot默认添加了如下4种HandlerAdapter
HandleAdapter接口定义如下
public interface HandlerAdapter {
boolean supports(Object hanlder);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
supports方法接受的就是HandlerExecutionChain的handler对象。比如,我们的示例返回的是HandlerMethod,HandlerMethod对应的是RequestMappingHandlerAdapter。
HandlerAdapter 的handle方法返回一个ModelAndView对象,其包含了数据模型和页面视图名称。
HandlerMethod实际上就是我们@RequestMapping注解的方法,它包含了@RequestMapping注解的方法的所有信息(方法名称、参数等等)。而我们@RequestMapping注解的方法实际上就是HandlerAdapter执行的。
ViewResolver
ViewResolver在SpringMVC中就是一种策略模式的实现。根据不同的实现类实现支持不同的视图。比如我们要支持freemarker,那么需要我们手动配置FreeMarkerViewResolver到Spring 容器
SpringBoot默认加载的视图解析器
总结
SpringMVC 主要的组件工作流程如下
关于ViewResolver本章介绍得很少,我们后续会讲到。