Spring MVC 是什么
SpringMVC 全名叫 Spring Web MVC,是⼀种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级Web 框架 。
SpringMvc开发web是非常方便的,那么它在背后做了什么工作呢?为什么咱们传统的servlet开发,几乎在spring中屏蔽了,只需要配置@Controller、@RequestMapping这些注解就能做业务逻辑开发呢?对于源码的阅读能让咱们理解这些方法。
DispatcherServlet源码阅读
要使用springmvc,必须要在web.xml中配置DispatcherServlet请求分发
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
先看看DispatcherServlet的类图结构,DispatcherServlet也是一个特殊的Servlet,它接管了请求,然后对每个请求进行分发处理。
spring九大组件的初始化
因为DispatcherServlet的分发需要使用到九大组件,所以咱了解下这些组件时怎么初始化的。
众所周知,Servlet的生命周期分别为:init(),service(),destory()三个阶段。DispatcherServlet的init方法在
org.springframework.web.servlet.HttpServletBean#init()中
public final void init() throws ServletException {
// 核心调用方法
initServletBean();
}
然后调用org.springframework.web.servlet.FrameworkServlet#initServletBean()方法进行webApplicationContext的初始化
protected final void initServletBean() throws ServletException {
try {
// 初始化initWebApplicationContext
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
}
当初始化完成后,会执行org.springframework.context.support.AbstractApplicationContext#finishRefresh()方法,触发刷新事件,最终调用到DispatcherServlet#onRefresh方法
// 初始化策略
initStrategies(context);
即初始化SpringMvc的九大组件
protected void initStrategies(ApplicationContext context) {
// 多文件上传的组件
initMultipartResolver(context);
// 初始化本地语言环境
initLocaleResolver(context);
// 初始化模板处理器
initThemeResolver(context);
// 初始化HandlerMapping
initHandlerMappings(context);
// 初始化参数适配器
initHandlerAdapters(context);
// 初始化异常拦截器
initHandlerExceptionResolvers(context);
// 初始化视图预处理器
initRequestToViewNameTranslator(context);
// 初始化视图转换器
initViewResolvers(context);
// 初始化 FlashMap 管理器
initFlashMapManager(context);
}
着重关注下initHandlerMappings进行HandlerMapping的初始化
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 检测所有的handlerMapping还是只需要“handlerMapping”bean
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 找到所有的HandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
// 否则在ioc中按照固定名称去找
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
// 最后还为空则按照默认策略生成
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
}
看看默认策略怎么生成的
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
// 从DispatcherServlet.properties加载defaultStrategies
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
return strategies;
}
else {
return new LinkedList<>();
}
}
看看DispatcherServlet.properties中配置,HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;配置了2个默认的HandlerMapping
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
spring的分发处理流程
看看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 {
// 1 检查是否是文件上传的请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
/*
2 取得处理当前请求的Controller,这里也称为Handler,即处理器
这里并不是直接返回 Controller,而是返回 HandlerExecutionChain 请求处理链对象
该对象封装了Handler和Inteceptor
*/
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 如果 handler 为空,则返回404
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 3 获取处理请求的处理器适配器 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 处理 last-modified 请求头省略代码........
// Actually invoke the handler.
// 4 实际处理器处理请求,返回结果视图对象
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);
}
// 触发异常捕获或者拦截器的执行完成事件执行
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//最终会调用HandlerInterceptor的afterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//最终会调用HandlerInterceptor的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);
}
}
}
}
可以看到doDispatch分发流程为:
检查是否是文件上传的请求
取得处理当前请求的Controller,这里也称为Handler,即处理器
这里并不是直接返回 Controller,而是返回 HandlerExecutionChain 请求处理链对象
该对象封装了Handler和Inteceptor
获取处理请求的处理器适配器 HandlerAdapter
对于HandlerMthod类型的handler对应的HandlerAdapter是RequestMappingHandlerAdapter,它继承于AbstractHandlerMethodAdapter,可从supports方法中看到它支持HandlerMethod类型的handler
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
实际处理器处理请求,返回结果视图对象
入口:
进入RequestMappingHandlerAdapter#invokeHandlerMethod方法后
进入ServletInvocableHandlerMethod#invokeAndHandle方法后
进入InvocableHandlerMethod#invokeForRequest方法后
进入InvocableHandlerMethod#doInvoke方法后,调用method进行处理。
protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { return getBridgedMethod().invoke(getBean(), args); }catch (Exception ex) { // 省略异常处理 } }
结果视图对象的处理
最终会调用HandlerInterceptor的afterCompletion 方法。
HandlerMethod的注册流程
每一个Controller类下的方法,只要含有springmvc的@RequestMapping注解,就会被当作一个handlerMethod注册到MappingRegistry中。
先看看RequestMappingHandlerMapping的类关系图
- 创建RequestMappingHandlerMapping对象的时候会执行afterPropertiesSet方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet()
- 然后调用父类org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods()
- 再调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods(Object handler)方法
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// 拿到符合映射关系的method,比如包含有RequestMapping注解等,并返回RequestMappingInfo
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
// ...........
}
});
methods.forEach((method, mapping) -> {
// 查找到最终的执行方法,有可能存在父类或接口中,并检查方法是否合法
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册到mappingRegistry中
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
- 最后看看org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register方法
// registry注册容器Map
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
// 注册方法
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
// 从BeanFactory中获取得到method对应的Spring Bean对象,封装到HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 校验是否唯一
assertUniqueMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 添加到registry Map中
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
// 释放锁
this.readWriteLock.writeLock().unlock();
}
}
// 从BeanFactory中获取得到method对应的Spring Bean对象,封装到HandlerMethod对象
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
HandlerMethod handlerMethod;
if (handler instanceof String) {
String beanName = (String) handler;
handlerMethod = new HandlerMethod(beanName,
obtainApplicationContext().getAutowireCapableBeanFactory(), method);
}
else {
handlerMethod = new HandlerMethod(handler, method);
}
return handlerMethod;
}