JAVA面试题之-SpringMVC的执行流程
1. 前言:
在java的面试过程中,如果是讨论框架方面的话,这个问题被问到的几率就很大;
身边朋友在面试的时候也会时不时的碰到,固总结在此。
2.概念:
那什么是springMVC呢?
它其实是一种我们做javaWeb开发的一种架构;包括MVC三个层次的架构;
M:modle:业务模型(也就是sevice+do/mapper层)
V:View,视图层(如jsp等前端显示层)
C:Controller,控制器(sevlet/javabean);
3.SpringMVC的执行流程:
4. 源码分析:
DispatcherServlet其实是一个Servlet,我们都知道在处理请求的时候会交给service方法进行处理;在DispatcherServlet类中继承了FrameworkServlet,
在FrameworkServlet中的service方法中:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
//其他请求类型的方法,经由父类,也就是HttpServlet处理;
super.service(request, response);
} else {
//如果请求类型的方法位PATCH,那么就用processRequest进行处理;
this.processRequest(request, response);
}
}
request.getMethod();是表示得到前端客户端传向服务器传送数据的方法;如GET,POST,HREADER,TRACE等;
而HttpMtheod中的resolve代码如下:还是前端的那些传送数据的方法,只是进行了封装;
public enum HttpMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
private static final Map<String, HttpMethod> mappings = new HashMap(16);
private HttpMethod() {
}
@Nullable
public static HttpMethod resolve(@Nullable String method) {
return method != null ? (HttpMethod)mappings.get(method) : null;
}
如果为PATCH,就会调用processRequest方法;而此方法中父类的doservice,因为子类实现了此方法,根据多态实际上使用的是DIsptcherServet中的doService方法;
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = this.buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
this.initContextHolders(request, localeContext, requestAttributes);
try {
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
再看DispatcherServlet中的doService方法:可以看到,会执行本类中的doDispatch方法;
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
//给request中的属性做一份快照;
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
//getAttribute ,setAttribute ,
Enumeration attrNames = request.getAttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
// 如果我们没有配置类似本地化或者主题的处理器之类的,springMVC 会使用默认的值;默认的配置文件是,DispathcerServlet.properties;
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.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 {
//开始执行
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
DispatcherServlet中的doDispatch方法;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//springMVC中的异步请求的管理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//先检查是不是multipart类型的,比如上传等,
//如果是multipart类型的,就转化为MultipartHttpServletRequest类型;
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//获得当前请求的Handler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 获得当前请求的HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
//对于header中的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方法进行处理;
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//真正调用handle的地方
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//处理默认视图名,即添加前缀后缀名
this.applyDefaultViewName(processedRequest, mv);
//拦截器postHandle进行处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//处理最后的结果,渲染之类的都在这里
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
// Clean up any resources used by a multipart request
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
//springmvc中关于dispatcherServlet中的步骤都在这;
查找请求对应的handle对象
对应的上面 mappedHandler = this.getHandler(processedRequest)代码;
具体getHandler()方法如下:
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//遍历所有的handlerMapping
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;
}
这个方法又调用了getHandler(request);在AbstractHandlerMapping类中,
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据request,获取handler;
Object handler = this.getHandlerInternal(request);
//如果没有找到就使用默认的handler
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
//如果handler属于String类,表示是一个bean的名称
//需要对照对应的bean
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
//封装handler执行链
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
//打印相关log信息
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
//判断是否是跨域问题;
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
//与跨域配置信息映射的容器
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
//得到跨域的handeler执行链
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
再看, 根据request,获取handler,
Object handler = this.getHandlerInternal(request);
往下追,在AbstractHandlerMethodMapping类中,源码为:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取request中的url,用来匹配handler
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
//根据路径寻找Handler;
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
// 根据HandlerMethod中的bean来实例化Handler并添加进HandlerMethod;
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
this.mappingRegistry.releaseReadLock();
}
return var4;
}
根据路径来寻找HandlerMethod;
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
源码:
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();//直接匹配
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
//如果有就直接添加到匹配列表中
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);
}
// 还没有匹配的,就遍历所有的处理方法查找
if (matches.isEmpty()) {
// No choice but to go through all
this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// 找到了1匹配的
if (!matches.isEmpty()) {
//排序之后,获取第一个
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
//如果有多个匹配的,会找到第二个最适合的进行比较一下
if (matches.size() > 1) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)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);
//设置request参数
this.handleMatch(bestMatch.mapping, lookupPath, request);
//返回匹配处理url的方法
return bestMatch.handlerMethod;
} else {// 最后还没有找到,返回null
return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
在AbstractHandlerMapping类中的getHandler方法中,对handler进行根据request的handler直接获取。
(具体在AbstracHandlerMethodMapping类中)
然候如果没有就
获取默认Handler
如果上面没有获取到Handler,就会获取默认的Handler。
如果还获取不到就返回null。
处理String类型的Handler
如果上面处理完的Handler是String类型的,
就会根据这个handlerName获取bean。
封装Handler执行链
上面获取完Handler,就开始封装执行链了,
就是将我们配置的拦截器加入到执行链中去,getHandlerExecutionChain:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//如果当前Handler不是执行链类型,就使用一个新的执行链实例封装起来
HandlerExecutionChain chain =
(handler instanceof HandlerExecutionChain) ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
//根据请求查询路径,获得当前的url
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
//先获取适配类型的拦截器添加进去拦截器链的迭代器
Iterator var5 = this.adaptedInterceptors.iterator();
while(var5.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
//遍历拦截器,找到跟当前url对应的,添加进执行链中去
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
//获取适配类型的拦截器添加进去拦截器链
chain.addInterceptor(interceptor);
}
}
return chain;
}
获取对应请求的Handler适配器: HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());(DispatcherServlet类中的doDipatch()方法中)
getHandlerAdapter:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
//遍历所有的HandlerAdapter,找到和当前Handler匹配的就返回
//我们这里会匹配到RequestMappingHandlerAdapter
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
缓存的处理
也就是对last-modified的处理
执行拦截器的preHandle方法
就是遍历所有的我们定义的interceptor,执行preHandle方法
使用Handler适配器执行当前的Handler:也就是:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
ha.handle执行当前handlerInternal,我们这里使用的是RequestMappingHandlerAdapter,首先会进入AbstractHandlerMethodAdapter的handle方法,然后该方法调用了本类的抽象的handlerInternal方法,RequestMappingHandlerAdapter集成了它:
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
// Execute invokeHandlerMethod in synchronized block if required.
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
//Always prevent caching in case of session attribute management.
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
//返回封装的ModelAndView的mav
return mav;
}
再往下追,就是把handler封装的handlerMethod,完成请求参数的封装,和jason格式的转换;
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
Object result;
try {
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (!asyncManager.isConcurrentHandlingStarted()) {
ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
return var15;
}
result = null;
} finally {
webRequest.requestCompleted();
}
return (ModelAndView)result;
}
组装默认视图名称
前缀和后缀名都加上
执行拦截器的postHandle方法
遍历intercepter的postHandle方法。
处理最后的结果,渲染之类的
DispatcherServlet类中的processDispatchResult方法:
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) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//渲染
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
if
// Concurrent handling started during a forward
(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
重点看下render方法,进行渲染:
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);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
//解析视图名,得到视图
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.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 '" + this.getServletName() + "'");
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//委托给视图进行渲染
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "]", var8);
}
throw var8;
}
}
view.render就是进行视图的渲染,然后跳转页面等处理。
到这里大概的流程就走完了。其中涉及到的东西还有很多,暂先不做详细处理。