文章目录
本系列结合源码(基于springboot2.1.4),分析springmvc的执行流程。
先上一个完整的流程图,借用网络上的:
我们知道,前端发起的请求首先到tomcat,最终执行的是servlet,springmvc实现了一个servlet,叫做DispatcherServlet,其继承关系如下:
假设发起一个get请求,这时,servlet中的doGet方法会执行,最终执行到DispatcherServlet,链路如下:
FrameworkServlet#doGet(HttpServletRequest request, HttpServletResponse response)
--》FrameworkServlet#processRequest(HttpServletRequest request, HttpServletResponse response)
--》DispatcherServlet#doService(HttpServletRequest request, HttpServletResponse response)
--》DispatcherServlet#doDispatch(HttpServletRequest request, HttpServletResponse response)
最终进入DispatcherServlet类的doDispatch方法中。
doDispatch()方法
这个方法是sprngmvc的核心方法,所有扭转乾坤的逻辑都在这里:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//处理器执行链,包含拦截器和具体的controller
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.
//确定要执行的mappedHandler,也就是要执行的controller
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//得到handler适配器,总共有3种
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//执行controller,得到model和view
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果没有view名字,设置一个默认的名字
applyDefaultViewName(processedRequest, mv);
//执行拦截器的postHandle方法
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);
}
//渲染视图,并将跳转路径设置到response中
//然后执行拦截器的afterCompletion方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//抛异常,也要执行拦截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
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);
}
}
}
}
主要步骤:
1.确定handlerMapping,并从其中得到HandlerExecutionChain执行链,这个执行链包含了拦截器以及controller方法路径;
2.确定handler适配器,总共有3种:
3.利用适配器执行handler,也就是controller,但是如果有拦截器,那么要先执行拦截器相关方法。
4.渲染视图并返回
关于handlerMapping和适配器在容器中的初始化在《SpringMVC系列(二)HandlerMapping初始化》中分析。
上面是springmvc大致的请求流程,下面针对具体方法详细分析。
getHandler(HttpServletRequest request)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
方法逻辑比较简单,就是遍历
这里handlerMappings是个list,默认有5个实例对象,共4种类型:
- SimpleUrlHandlerMapping
- RequestMappingHandlerMapping,处理@Controller修饰的类中,@RequestMapping修饰的方法
- BeanNameUrlHandlerMapping
- SimpleUrlHandlerMapping,类型同第一个,但是是不同的实例对象
- WelcomePageHandlerMapping,默认应用欢迎页面
遍历然后调用mapping.getHandler(request)方法获取HandlerExecutionChain。
其中getHandler方法是在父类AbstractHandlerMapping种实现:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//得到handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
//得到执行链,就是添加上拦截器
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;
}
第一行代码 getHandlerInternal(request),进入:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
handlerMethod最终是在mappingRegistry中获取到;
mappingRegistry中维护了多种map,其中就有请求路径和处理方法映射的map,根据请求信息,就可以直接从map中get到。
关于mappingRegistry中的map数据是如何来的,我们在下一篇文章《SpringMVC系列(二)HandlerMapping初始化》中分析。
上面得到handler后,还不是最终要返回的对象,最终返回的是HandlerExecutionChain 类型对象,是个执行链,包含了拦截器,因为要先执行拦截器在执行相关handler方法,
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) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
//判断拦截器的配置,当前方法是否被此拦截器拦截
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
spring容器在启动的时候,会预先加载所有拦截器,这里进行遍历,判断拦截器的拦截内容,如果符合拦截条件,就将拦截器add到HandlerExecutionChain 对象中形成执行链路。
handlerMapping分析到这,下面HandlerAdapter流程也是类似的。
getHandlerAdapter(Object handler)
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
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");
}
HandlerAdapter默认有如下3种,初始化流程和HandlerMpping类似,
- RequestMappingHandlerAdapter
- HttpRequestHandlerAdapter
- SimpleControllerHandlerAdapter
上述代码逻辑也是遍历各种Adapter,找到后直接返回。
processDispatchResult()
上面找到HandlerMapping后,得到具体的执行方法,然后使用Adapter执行,最终得到ModelAndView视图,然后使用如下方法进行视图的渲染操作,
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) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//进行渲染动作
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
执行渲染动作的是渲染方法render,
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
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 {
// No need to lookup: the ModelAndView object contains the actual View object.
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() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}