SpringMvc处理分发请求原理

在Spring MVC中是通过DispatcherServlet前端控制器来完成所有Web请求的转发匹配数据处理后,并转由页面进行展示,是MVC实现中最核心的部分。

DispatcherServlet是继承的FrameworkServlet,而FrameworkServlet是HttpServlet的子类,FrameworkServlet对诸如doGet、doPost等所有放法进行了重写,都调用processRequest方法,让后调用子类DispatcherServletdoService方法,最终调用doDispatch方法处理转发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class DispatcherServlet extends FrameworkServlet {
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); // 把Spring上下文对象存放到Request的attribute中
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); // 把Spring国际化支持解析器对象存放到Request的attribute中
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); // 主题解析器对象
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); // 主题对象
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}

try {
doDispatch(request, response); // 真正的进行处理转发
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
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); // 检查request对象判断请求是不是文件上传的请求
// 判断是不是文件上传请求,若是则返回的processedRequest是MultipartHttpServletRequest,显然和原始的request对象不是同一个对象
multipartRequestParsed = (processedRequest != request);
// 从当前的请求中推断出HandlerExecuteChain处理器执行链对象
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据Handler选择HandlerAdpater对象,默认是@RequestMappingHandlerAdapter对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//触发拦截器的pre方法,返回false,就不进行处理了
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 通过适配器真正的调用目标方法,RequestMappingHandlerAdapter.handle=>AbstractHandlerMethodAdapter#handle(HttpServletRequest, HttpServletResponse,Object)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 触发拦截器链的post方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理目标方法返回的结果,主要是渲染视图
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()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest); // 清除文件上传时候生成的临时文件
}
}
}
}
}

处理器映射器HandlerMapping

初始化完成时,在上下文环境中已定义的所有HandlerMapping都已被加载放到一个排好序的List中,存储着HTTP请求对应的映射数据,每个HandlerMapping可持有一系列从URL请求到Controller的映射。对于不同Web请求的映射,Spring MVC提供了不同的HandlerMapping的实现,可让应用开发选取不同的映射策略,XML方式通过在web.xml中配置的方式注册Bean默认使用BeanNameUrlHandlerMapping映射策略,通过@Controller@RequestMapping注解的方式使用RequestMappingHandlerMapping映射策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// Web容器中配置的所有的handlerMapping集合对象在本类中的initHandlerMappings()方法为DispatcherServlet类初始化赋值handlerMappings集合
if (this.handlerMappings != null) {
// 循环遍历所有的handlerMappings对象,依次调用handlerMappings的getHandler(request)来获取处理器执行链对象
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
// 依次循环调用HandlerMapping的getHandler方法进行获取HandlerExecutionChain,调用所有的HandlerMapping的父类的AbstractHandlerMapping#getHandler(request)
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
// 通过所有的handlerMapping对象 还没有获取到对应的HandlerExecutionChain,则认为该请求无法匹配
return null;
}

首先通过UrlPathHelper对象解析出request中请求路径,让后通过该路径到RequestMappingHanlderMapping的路径映射注册表mappingRegistry中匹配,匹配到后通过getHandlerExecutionChain将其封装成一个HandlerExecutionChain,然后匹配拦截器规则,将满足条件的拦截器添加到该封装对象中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 找到处理器对象,在本子类的AbstractHandlerMapping的子类RequestMappingHanlderMapping的生命周期回调接口InitializingBean中会把@RequestMapping注解信息和方法映射对象保存到路径映射注册表中
Object handler = getHandlerInternal(request);
if (handler == null) { // 判断上一步的handler是否为空
handler = getDefaultHandler(); // 返回默认的handler
}
if (handler == null) {
return null;
}
if (handler instanceof String) { // 若解析出的handler是String则通过Web容器创建handler对象
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 根据处理器来构建处理器执行链对象
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) { // 处理跨域
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建处理器执行链对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 从请求中获取请求映射路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 循环获取所有的拦截器对象
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 判断拦截器对象是不是实现HandlerInterceptor
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 通过路径匹配看该拦截器是否会拦截本次请求路径
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain; // 返回我们的拦截器链执行器对象
}
}
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取UrlPathHelper对象,用于解析从request中解析出请求映射路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock(); // 通过映射注册表获取lock对象
try {// 通过从Request对象中解析出来的lookupPath然后通过lookupPath获取HandlerMethod对象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {// 释放锁对象
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 根据路径去MappingRegistry注册表中的urlLookup的map对象中获取RequestMappingInfo对象,mappingRegistry在RequestMappingHandlerMapping的bean的初始化方法就进行解析保存到注册表中
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
// 判断通过解析出来的lookUpPath解析出来的RequestMappingInfo不为空 把RequestMappingInfo封装成为Match保存到集合中
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); // 创建Match的匹配器对象
matches.sort(comparator); // 对匹配器进行排序
Match bestMatch = matches.get(0); // 默认选择第一个为最匹配的
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1); // 获取第二最匹配的
if (comparator.compare(bestMatch, secondBestMatch) == 0) { // 若第一个和第二个是一样的则抛出异常
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); // 把最匹配的设置到request中
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod; // 返回最匹配的
} else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
}

处理器适配器HandlerAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class DispatcherServlet extends FrameworkServlet {
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) { // 循环系统配置配置的handlerAdapters
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
}
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
public final boolean supports(Object handler) {
// 判断hanlder是不是HandlerMethod实现类或者子类 && 默认返回true
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
}

Spring MVC采用适配器模式来适配调用指定Handler,根据Handler的不同种类采用不同的Adapter,其对应关系如下:

Handler类别 对应适配器 描述
Controller SimpleControllerHandlerAdapter 标准控制器,返回ModelAndView,实现Controller接口
HttpRequestHandler HttpRequestHandlerAdapter 实现HttpRequestHandler接口
Servlet SimpleServletHandlerAdapter 基于标准的Servlet处理,继承HttpServlet
HandlerMethod RequestMappingHandlerAdapter 基于@RequestMapping对应方法处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class SimpleController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
public class HttpRequestController implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
public class ServletController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
@Controller
public class RequestController {
@RequestMapping(value = "/hello")
public String hello() {
return "a";
}
}

执行处理器方法过程

通过上面获取的具体的HandlerAdapter调用具体的handle方法,RequestMappingHandlerAdapter是调用超类AbstractHandlerMethodAdapter的handle方法从而调用自身的handleInternal方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return handleInternal(request, response, (HandlerMethod) handler); // 调用到具体子类的方法
}
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request); // 检查请求对象
// 判断当前是否需要支持在同一个session中只能线性地处理请求,synchronized是JVM进程级,故分布式环境下,无法达到同步Session的功能。默认情况下synchronizeOnSession为false
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false); // 获取当前请求的session对象
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session); // 为当前session生成一个唯一的可用于锁定的key
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod); // 对HandlerMethod进行参数等的适配处理,并调用目标handler
}
} else {// 若当前不存在session,则直接对HandlerMethod进行适配
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else { // 若当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
// 若当前SessionAttribute中存在配置的attributes,则为其设置过期时间。这里SessionAttribute主要是通过@SessionAttribute注解生成的
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else { // 若当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,若存在则按照该设置进行response处理,若不存在则设置response中的Cache的过期时间为-1,即立即失效
prepareResponse(response);
}
}
return mav;
}
}

首先获取容器中全局配置的InitBinder当前HandlerMethod所对应的Controller中配置的InitBinder用于参数的绑定,然后获取容器中全局配置的ModelAttribute当前HandlerMethod所对应的Controller中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用。

将handlerMethod封装为一个ServletInvocableHandlerMethod对象,该对象用于对当前request的整体调用流程进行了封装,设置参数解析器对象,设置返回值解析对象,并将前面创建的WebDataBinderFactory也设置到ServletInvocableHandlerMethod中,然后通过initModel()方法调用前面获取到的@ModelAttribute标注的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response); // 把请求req resp包装成ServletWebRequest
try {
// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中配置的InitBinder,用于参数的绑定
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 将handlerMethod封装为一个ServletInvocableHandlerMethod对象,该对象用于对当前request的整体调用流程进行了封装HanlderMethod:InvocableHandlerMethod:invokeForRequest(),ServletInvocableHandlerMethod:invokeAndHandle()
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 为invocableMethod(ServletInvocableHandlerMethod)设置参数解析器对象argumentResolvers的初始化就是在RequestMappingHandlerAdapter的生命周期回调afterPropertiesSet()方法进行对argumentResolvers初始化赋值,用于解析参数
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 为invocableMethod(ServletInvocableHandlerMethod)设置参数解析器对象argumentResolvers的初始化就是在RequestMappingHandlerAdapter的生命周期回调afterPropertiesSet()方法进行对returnValueHandlers初始化赋值,用于解析返回值
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 将前面创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
invocableMethod.setDataBinderFactory(binderFactory);
// 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 这里initModel()方法主要作用是调用前面获取到的@ModelAttribute标注的方法,从而达到@ModelAttribute标注的方法能够在目标Handler调用之前调用的目的
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 调用我们标注了@ModelAttribute的方法,主要是为目标方法预加载
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 重定向时,忽略model中的数据
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 获取当前AsyncWebRequest,主要作用是判断目标handler返回值是否为WebAsyncTask或DefferredResult,若是则说明当前请求的处理应该是异步的。
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 封装异步任务的线程池,request和interceptors到WebAsyncManager中
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 这里就是用于判断当前请求是否有异步任务结果的,如果存在,则对异步任务结果进行封装
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,还会判断是否需要将FlashAttributes封装到新的请求中
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {// 调用request destruction callbacks和对SessionAttributes进行处理
webRequest.requestCompleted();
}
}
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType(); // 获取HandlerMethod的class类型
Set<Method> methods = this.initBinderCache.get(handlerType); // 尝试从缓存中加载Controller中的标注了@InitBinder注解的方法
if (methods == null) { // 缓存中没有,则查找Controller中标注@InitBinder注解的方法
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods); // 加入到局部缓存initBinder中
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>(); // 定义一个initBinderMethod的集合
// 全局的initBinder注解全局一般是在@ControllerAdvice的类中,initBinderAdviceCache缓存变量在RequestMappingHandlerAdapter类的afterPropertiesSet方法中去加载的
this.initBinderAdviceCache.forEach((clazz, methodSet) -> {
if (clazz.isApplicableToBeanType(handlerType)) { // 判断全局的webInitBinder能否作用到当前的controller中
Object bean = clazz.resolveBean();
for (Method method : methodSet) { // 把方法加入到集合中
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
});
for (Method method : methods) { // 合并局部的initbinder和全局的initbinder
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
return createDataBinderFactory(initBinderMethods); // 创建数据绑定器工厂
}
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
// 获取SessionAttributesHandler,解析类上标注的@SessionAttributes注解
// 若类上标注了@SessionAttributes注解,则目标返回模型数据就回被放到session中
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
Class<?> handlerType = handlerMethod.getBeanType(); // 获取目标controller的class对象
Set<Method> methods = this.modelAttributeCache.get(handlerType); // 尝试从modelAttributeCache缓存中获取对象

if (methods == null) { // 缓存中没有该对象
// 若缓存中没有相关属性,则在当前bean中查找所有使用@ModelAttribute标注,但是没使用@RequestMapping标注的方法,并将这些方法缓存起来
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods); // 加入到缓存中
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
this.modelAttributeAdviceCache.forEach((clazz, methodSet) -> { // 获取全局的标注了@ControllerAdivce中的@ModelAttribute注解的方法
// 判断标注了@ControllerAdivce类型全局@ModelAttribute注解的能否匹配当前的class对象
if (clazz.isApplicableToBeanType(handlerType)) {
Object bean = clazz.resolveBean();
for (Method method : methodSet) { // 创建InvocableHandlerMethod加入到缓存中
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
});
for (Method method : methods) { // 合并全局和局部的@ModelAttribute方法
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);//创建ModelFactory返回
}

最终通过invokeAndHandle中调用invokeForRequestInitBinder配置的方法和具体的Controller方法进行调用,对于InitBinder方法的具体调用是在getMethodArgumentValues方法中resolveArgument调用具体的参数解析器来完成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 真正的调用目标对象
setResponseStatus(webRequest); // 设置相关的返回状态
if (returnValue == null) { // 如果请求处理完成,则设置requestHandled属性
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return; // 如果请求失败,但是有错误原因,那么也会设置requestHandled属性
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {// 遍历当前容器中所有ReturnValueHandler,判断哪种handler支持当前返回值的处理,若支持,则使用该handler处理该返回值
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); // 获取目标方法入参的值
Object returnValue = doInvoke(args); // 真的的调用目标方法
return returnValue;
}
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters(); // 获取目标方法参数的描述数组对象
Object[] args = new Object[parameters.length]; // 用来初始化对应参数名称的参数值得数组
for (int i = 0; i < parameters.length; i++) { //循环参数名数组
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); // 为MethodParameter设置参数名称探测器对象
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) { // 获取所有的参数解析器,然后筛选出合适的解析器
try {//通过参数解析器来解析参数
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
continue;
} catch (Exception ex) {
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " + parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() + ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); // 通过参数筛选出参数解析器对象
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
// 挑选参数解析器来解析真正的参数值
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 获取能够处理当前返回值的Handler,比如如果返回值是ModelAndView类型,那么这里的handler就是ModelAndViewMethodReturnValueHandler
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 通过获取到的handler处理返回值,并将其封装到ModelAndViewContainer中
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

视图解析器

视图解析器ViewResolver负责将处理结果生成View视图,首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示。视图对象是由视图解析器负责实例化

视图解析器作用将逻辑视图转为物理视图,所有的视图解析器都必须实现ViewResolver接口。SpringMVC为逻辑视图名的解析提供了不同的策略,可在Spring WEB上下文中配置一种多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。可选择一种视图解析器或混用多种视图解析器。可通过order属性指定解析器的优先顺序,order越小优先级越高,SpringMVC会按视图解析器的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出ServletException异常。

分类 解析器类型 说明
解析为Bean的名称 BeanNameViewResolver Bean的id即为逻辑视图名称。
解析为URL文件 InternalResourceViewResolver 将视图名解析成一个 URL 文件。
解析指定XML文件 XmlViewResolver 解析指定位置的XML文件,默认在/WEB-INF/views.xml
解析指定属性文件 ResourceBundleViewResolver 解析properties文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) { // 异常页面处理
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) { //渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取国际化语言解析器对象
Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();//获取视图名称
if (viewName != null) {// 根据的视图名称通过视图解析器对象解析成为真正的物理视图
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + getServletName() + "'");
}
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response); //渲染模型视图
} catch (Exception ex) {
throw ex;
}
}

根据的视图名称通过视图解析器对象解析成为真正的物理视图,最终调用AbstractCachingViewResolver的createView然后调用具体的视图解析器去创建物理视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) { //判断当前的视图解析器集合是否为空
for (ViewResolver viewResolver : this.viewResolvers) { //循环调用的视图解析器对象解析视图
// 一旦有的视图解析器能够解析出视图,后面的视图解析器不在参与解析直接返回
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
public View resolveViewName(String viewName, Locale locale) throws Exception {
// 是否启用缓存,可通过setCache()方法或setCacheLimit()方法开启缓存,是一个ConcurrentHashMap,默认缓存大小1024,可在配置视图解析器的时候,配置是否启用缓存默认情况下为了提升性能是开启的
if (!isCache()) {
return createView(viewName, locale);
} else {
Object cacheKey = getCacheKey(viewName, locale); // 获取缓存的key:viewName + '_' + locale;
View view = this.viewAccessCache.get(cacheKey); // 尝试去缓存中加载
if (view == null) { // dcl,防止并发解析
synchronized (this.viewCreationCache) {
view = this.viewCreationCache.get(cacheKey);
if (view == null) {
view = createView(viewName, locale); // 调用子类去创建视图对象
if (view == null && this.cacheUnresolved) {
view = UNRESOLVED_VIEW;
}
if (view != null) {
this.viewAccessCache.put(cacheKey, view);
this.viewCreationCache.put(cacheKey, view);
if (logger.isTraceEnabled()) {
logger.trace("Cached view [" + cacheKey + "]");
}
}
}
}
}
return (view != UNRESOLVED_VIEW ? view : null);
}
}
public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver {
protected View createView(String viewName, Locale locale) throws Exception {
return loadView(viewName, locale); //加载一个视图
}
}
分类 视图类型 说明
URL视图 InternalResourceView 将JSP或者其他资源封装成一个视图,
InternaleResourceViewResolver默认视图类型。
JstlView 当在页面中使用了JSTL标签库的国际
化标签后,需要采用的类型。
文档类视图 AbstractPdfView PDF文档视图的抽象类
AbstarctXlsView 4.2之后加入,Excel文档视图的抽象类
之前使用AbstractExcelView
JSON视图 MappingJackson2JsonView 将模型数据封装成Json格式数据输出
需借助Jackson开源框架。
XML视图 MappingJackson2XmlView 4.1后加入,将模型数据封装成XML格式数据

视图的作用是渲染模型数据,将模型里的数据以某种形式呈现。为了实现视图模型和具体实现技术的解耦,Spring在org.springframework.web.servlet包中定义了一个高度抽象的View接口。通过renderMergedOutputModel调用具体的视图类去渲染视图。

1
2
3
4
5
6
7
8
9
public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); // 获取模型数据
prepareResponse(request, response); // 设置响应头
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}