前言
spring boot 中的spring mvc 和spring4.0之前的版本在启动的时候有些差异, 以前springMVC主要是通过web.xml中配置servlet
来完成spring MVC的启动。 但是在spring boot主要是通过DispatcherServletAutoConfiguration来完成初始化工作,下面可以主要来看一下
源码版本:spring-mvc 4.3.9
1.DispatcherServletAutoConfiguration
DispatcherServletAutoConfiguration
在类上声明了如**解:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration @ConditionalOnWebApplication @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class) |
1. @AutoConfigureOrder 自动化配置加载的顺序
2. @Configuration 表明这是一个配置类 , 交给spring容器管理
3. @ConditionalOnWebApplication 表示只在web环境才加载这个类
4. @ConditionalOnClass(DispatcherServlet.class) 表示只有在DispatcherServlet存在的情况才会记在这个类,可见后面主要就是通过这个servlet来完成
spring MVC的主要工作的
5. @AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class) 在这个类之后加载
在这个类中有两个静态内部类DispatcherServletConfiguration, DispatcherServletRegistrationConfiguration , 这两个类里面完成了大部分的初始化工作
DispatcherServletConfiguration
@Configuration // 表明是一个配置类
@Conditional(DefaultDispatcherServletCondition.class) // 通过该类来判断是否加载这个bean
@ConditionalOnClass(ServletRegistration.class) // ServletRegistration存在的情况下才进行加载
@EnableConfigurationProperties(WebMvcProperties.class) // 加载MVCProperties的配置类
protected static class DispatcherServletConfiguration {
private final WebMvcProperties webMvcProperties;
public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) {
this.webMvcProperties = webMvcProperties;
}
// DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = dispatcherServlet
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
// 初始化DispatcherServlet
DispatcherServlet dispatcherServlet = new DispatcherServlet();
// 设置是否允许分发Option请求,默认为true
dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest( this.webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
return dispatcherServlet;
}
// 初始化上传文件的解析器
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) // 当容器中不存在multipartResolver 这个bean的时候,就初始化这个bean
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
} |
看一下DefaultDispatcherServletCondition 这个类, 这个类主要是一些逻辑判断,判断容器中是否存在dispatcherServlet,
防止重复生成
@Order(Ordered.LOWEST_PRECEDENCE - 10)
private static class DefaultDispatcherServletCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("Default DispatcherServlet");
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
List<String> dispatchServletBeans = Arrays.asList(beanFactory
.getBeanNamesForType(DispatcherServlet.class, false, false));
//如果beanFactory 中存在id 为 dispatcherServlet,类型为DispatcherServlet的bean ,返回不匹配.否则进入下一步
if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
return ConditionOutcome.noMatch(message.found("dispatcher servlet bean")
.items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
}
// 如果beanFactory中包含id为dispatcherServlet的bean,返回不匹配
if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
return ConditionOutcome
.noMatch(message.found("non dispatcher servlet bean")
.items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
}
// 如果beanFactory中不包含类型为DispatcherServlet的bean,返回匹配
if (dispatchServletBeans.isEmpty()) {
return ConditionOutcome
.match(message.didNotFind("dispatcher servlet beans").atAll());
}
// 其他情况下,默认返回匹配
return ConditionOutcome.match(message
.found("dispatcher servlet bean", "dispatcher servlet beans")
.items(Style.QUOTE, dispatchServletBeans)
.append("and none is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
}
}
|
看一下WebMvcProperties这个类,这个类主要是读取配置文件,关键点就是在于类头上的一个注解,他就是为了读取配置文件中 “spring.mvc”开头的配置
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
/**
* Formatting strategy for message codes (PREFIX_ERROR_CODE, POSTFIX_ERROR_CODE).
*/
private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
/**
* Locale to use. By default, this locale is overridden by the "Accept-Language"
* header.
*/
private Locale locale;
/**
* Define how the locale should be resolved.
*/
private LocaleResolver localeResolver = LocaleResolver.ACCEPT_HEADER;
/**
* Date format to use (e.g. dd/MM/yyyy).
*/
private String dateFormat;
/**
* Dispatch TRACE requests to the FrameworkServlet doService method.
*/
private boolean dispatchTraceRequest = false;
/**
* Dispatch OPTIONS requests to the FrameworkServlet doService method.
*/
private boolean dispatchOptionsRequest = true;
/**
* If the content of the "default" model should be ignored during redirect scenarios.
*/
private boolean ignoreDefaultModelOnRedirect = true;
.........省略诸多代码
}
|
DispatcherServletRegistrationConfiguration
该类主要作用是为了将dispatcherServlet 注册到系统(servlet)里面去。
@Configuration // 表明为一个配置类
@Conditional(DispatcherServletRegistrationCondition.class) // 判断容器里面是否存在dispatcherServlet这个类,必须在存在的情况下才会创建这个bean
@ConditionalOnClass(ServletRegistration.class) // 在ServletRegistration 这个类存在的情况进行加载
@EnableConfigurationProperties(WebMvcProperties.class) //属性文件配置类
@Import(DispatcherServletConfiguration.class) // 导入DispatcherServletConfiguration
protected static class DispatcherServletRegistrationConfiguration {
private final ServerProperties serverProperties; // 服务器配置 ,读取server.x这种配置
private final WebMvcProperties webMvcProperties; // mvc配置
private final MultipartConfigElement multipartConfig;
public DispatcherServletRegistrationConfiguration(
ServerProperties serverProperties, WebMvcProperties webMvcProperties,
ObjectProvider<MultipartConfigElement> multipartConfigProvider) {
this.serverProperties = serverProperties;
this.webMvcProperties = webMvcProperties;
this.multipartConfig = multipartConfigProvider.getIfAvailable();
}
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public ServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
// 将dispatcherServlet通过ServletRegistrationBean 注册为servlet,如此该servlet才会生效
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet, this.serverProperties.getServletMapping());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
// 加载优先级 , getLoadOnStartup() 默认值为-1
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
} |
通过上面的代码分析,可以非常清晰的看到,spring mvc主要是依靠DispatcherServletAutoConfiguration 这个类中的两个内部类进行初始化,
DispatcherServletConfiguration负责生成dispatcherServlet
DispatcherServletRegistrationConfiguration 负责将dispatcherServlet注册到系统里面的servlet中,使其生效
两者配合,最终完成初始化工作。
2.DispatcherServlet
在spring创建完applicationContext后,会调用该类中的initStrategies方法 , 用于初始化spring mvc相关配置
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);//文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析
initLocaleResolver(context);//本地化解析
initThemeResolver(context);//主题解析
initHandlerMappings(context);//通过HandlerMapping,将请求映射到处理器
initHandlerAdapters(context);//通过HandlerAdapter支持多种类型的处理器, 将请求与映射到的方法做一个适配
initHandlerExceptionResolvers(context);//如果执行过程中遇到异常,将交给HandlerExceptionResolver来解析
initRequestToViewNameTranslator(context);//直接解析请求到视图名
initViewResolvers(context);//通过viewResolver解析逻辑视图到具体视图实现
initFlashMapManager(context);//flash映射管理器
} |
下面主要看一下doDispatch这个方法,所有的请求,都会集中到这里来进行分发处理
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 判断是否是上传文件
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 获取方法执行的handler , 此处主要是通过handleMappings ,然后gethandle
// 通过请求地址,从mappingRegistry通过请求路径获取到对应的handlerMethod
// 之后获取拦截器,获取拦截器的执行列表。
// 后面会重点讲这个方法
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取请求适配器,用于适配request和HandlerMethod最终执行的信息适配
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行拦截器列表里面的preHandle方法,如果有一个执行失败,那么则return ,这也是为什么prHandle方法可以阻止请求的执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler. 执行方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 执行拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) { //上述调用的过程中如果发生异常
dispatchException = ex;
}
catch (Throwable err) { //上述调用的过程中如果发生异常
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 由ViewResolver组件根据ModelAndView对象得到实际的View
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 发生异常,调用拦截器的AfterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 发生异常,调用拦截器的AfterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
} |