1、DispatcherServlet
前端控制器,SpringMVC里最核心的组件,是整个SpringMVC请求流程的中心,主要流程都是由DispatcherServlet来调用其他组件,而且看名字就知道,它是一个Servlet
2、HandlerMapping
处理器映射器,根据请求来查找对应的处理器Handler,其实就是Controller
3、Handler(Controller)
处理器,由软件工程师开发,其实就是Controller,用于具体处理用户的请求
4、HandlerAdapter
处理器适配器,因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就可以了,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法,所以如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就要用到HandlerAdapter了
注:网上看到一个很有意思的形容:
Handler是用来干活的工具
HandlerMapping用来根据需要干的活找到对应的工具
HandlerAdapter是使用工具干活的人
5、ViewResolver
视图解析器,根据视图名称解析成View类型的视图,View是用来渲染页面的,也就是将程序返回的数据填入模板里,生成html或者其他类型的文件,具体使用哪个模板,用什么规则填入数据就是ViewResolver要做的事,然后具体的渲染交给View去做
流程梳理:
1、用户通过浏览器发送请求到前端控制器(DispatcherServlet)
2、前端控制器(DispatcherServlet)将用户请求交给处理器映射器(HandlerMapping)
3-4、处理器映射器(HandlerMapping)找到负责这个请求的处理器(Handler)并和拦截器链一起封装成处理器执行链(HandlerExecutionChain)交给前端控制器(DispatcherServlet)
5、前端控制器(DispatcherServlet)会根据处理器(Handler)找到对应的处理器适配器(HandlerAdaptor)
6-9、处理器适配器(HandlerAdaptor) 会去执行具体的Controller,Controller将处理结果及要跳转的视图封装到ModelAndView返回给处理器适配器(HandlerAdaptor),并在执行Controller前后调用拦截器链
10、处理器适配器(HandlerAdaptor) 将ModelAndView返回给前端控制器(DispatcherServlet)
11、前端控制器(DispatcherServlet)将ModelAndView交给视图解析器(ViewResolver)
12、视图解析器(ViewResolver)将ModelAndView解析为具体的视图(View)返回给前端控制器(DispatcherServlet)
13、前端控制器(DispatcherServlet)调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中) ,形成响应 (HttpResponse)
14、前端控制器(DispatcherServlet)将响应 (HttpResponse) 返回给浏览器
首先我们要先知道SpringMVC的Servlet分为三层HttpServletBean、FrameworkServlet和DispatcherServlet,我们知道Servlet的入口是service方法,FrameworkServlet重写了service方法,我们往里跟代码,最终会来到DispatcherServlet的核心方法doDispatch
//DispatcherServlet
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);
//获取处理器,注意这里的mappedHandler里包含了handler和拦截器链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//找不到处理器,报404
noHandlerFound(processedRequest, response);
return;
}
//根据处理器里的handler获取对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//处理last-modified请求头
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;
}
}
//在处理请求前先执行拦截器的preHandle方法,这个方法会返回一个boolean类型的值
//如果是true,就交给后面的拦截器继续处理,
//如果是false就表示处理完了,顺便也把response搞定
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//用适配器处理请求,返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//判断是否需要viewNameTranslator从request里获取view的名字
applyDefaultViewName(processedRequest, mv);
//执行拦截器的PostHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//页面渲染,调用拦截器的afterCompletion方法等
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
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);
}
}
}
}
//获取处理器,注意这里的mappedHandler里包含了handler和拦截器链
mappedHandler = getHandler(processedRequest);
首先我们看下18行的getHandler方法,对应流程图中的2-4步
//DispatcherServlet
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
//逐个使用HandlerMapping去获取Handler,如果获取到了就返回,没获取到就换下一个
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
这里的handlerMappings是个List集合,HandlerMapper有很多实现类,最重要的就是RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,我们记住这两个类,继续看第7行getHandler,进入到AbstractHandlerMapping类里
//AbstractHandlerMapping
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
//找到匹配的拦截器和handler一起封装成一个HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
核心逻辑是第6行的getHandlerInternal,getHandlerInternal是个模板方法,最终会调用子类实现,这里有两个重要的实现类,分别是AbstractHandlerMethodMapping和AbstractUrlHandlerMapping,上面我们提到HandlerMapper有两个非常主要的实现类:RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,我们看看这两个类的类图
我们发现RequestMappingHandlerMapping是AbstractHandlerMethodMapping的子类,而BeanNameUrlHandlerMapping是AbstractUrlHandlerMapping的子类
RequestMappingHandlerMapping:主要用来存储RequestMapping注解相关的控制器和url的映射关系
BeanNameUrlHandlerMapping: 主要用来处理Bean name直接以 / 开头的控制器和url的映射关系。
我们最常用的其实还是RequestMappingHandlerMapping,所以我们进入AbstractHandlerMethodMapping的getHandlerInternal方法,继续看
//AbstractHandlerMethodMapping
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取requestMapping地址
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
//查找Handler
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
第9行核心方法进去
//AbstractHandlerMethodMapping
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List matches = new ArrayList<>();
//从mappingRegistry中获取命中的方法
List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//寻找合适的mapping,根据属性去精确查找,最终防到matches中
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
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();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
具体看下第9行addMatchingMappings
private void addMatchingMappings(Collection mappings, List matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
这里有个mappingRegistry很重要,mappingRegistry.getMappings,返回的是HandlerMethod的map,这一步相当于把匹配到的HandlerMethod封装到Match对象中,最后加到matches集合里,最后排序,取出第一个匹配的Handler返回
我们回到getHandler方法
//AbstractHandlerMapping
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
//找到匹配的拦截器和handler一起封装成一个HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
第6行返回的就是刚才的HandlerMethod对象,然后调用getHandlerExecutionChain方法,将HandlerMethod和拦截器链封装成HandlerExecutionChain对象返回
//用适配器处理请求,返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
下面看第47行handle方法,点击进到实现类AbstractHandlerMethodAdapter的handle方法中
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
继续点击handleInternal进入子类RequestMappingHandlerAdapter的handleInternal方法中
//RequestMappingHandlerAdapter
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
//检查是否支持当前request的请求方式和session
checkRequest(request);
//如果需要,在同步块中执行invokeHandlerMethod。
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
//无HttpSession可用->无需互斥
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
//不需要同步会话
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
最终会调用invokeHandlerMethod方法,点击进去
//RequestMappingHandlerAdapter
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//省略...
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
继续点击10行invokeAndHandle进到类ServletInvocableHandlerMethod中
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//重点
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
点击5行invokeForRequest进入其父类InvocableHandlerMethod中
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取方法参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
//执行具体业务
return doInvoke(args);
}
其中doInvoke方法最终会通过反射调用到Controller上的方法,我们具体看看getMethodArgumentValues方法
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取Controller对应的方法所有参数,该部分在程序启动时就已经解析好了
if (ObjectUtils.isEmpty(getMethodParameters())) {
return EMPTY_ARGS;
}
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);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//解析参数并赋值,这里会根据参数找到对应的解析器进行解析
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
String error = ex.getMessage();
if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, error));
}
}
throw ex;
}
}
return args;
}