SpringMVC源码分析之DispatcherServlet的执行流程
SpringMVC源码分析之DispatcherServlet1.DispatcherServlet的初始化前面一片文章大概的讲述了DispatcherServlet的基本作用,也知道它其实就是一个Servlet,下面详细分析DispatcherServlet。Web容器初始化后,会为每个Servlet创建对象,并加载其上下文环境。我们都知道,在Tomcat容器中,维护了一个线程池,...
SpringMVC源码分析之DispatcherServlet
1.DispatcherServlet的初始化
前面一片文章大概的讲述了DispatcherServlet的基本作用,也知道它其实就是一个Servlet,下面详细分析DispatcherServlet。
Web容器初始化后,会为每个Servlet创建对象,并加载其上下文环境。我们都知道,在Tomcat容器中,维护了一个线程池,每当有一个客户请求抵达服务器的时候,就分配一个线程来处理该请求。同时,Servlet是单例多线程的,也就是多个请求共用一个Servlet容器。所以呢,DispatcherServlet的完整定义是:是一个具有唯一性的增强型Servlet容器。 明确了这一点,我们就可以想象的到,DispatcherServlet具有servlet的大多数特性,包括Servlet的完整生命周期。
Spring中通过DispatcherServlet来处理所用的请求!为什么这样设计呢?具体可以参考前端设计模式
分析初始化之前先了解一下DispatcherServlet的继承关系:
首先了解到Servlet的初始化时会调用其inti(),DispatcherServlet也不例外。发现DispatcherServlet中没有该方法,继续向上看。FrameworkServlet中也没有,继续向上;发现HttpServletBean存在。
public final void init() throws ServletException {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//这里就是加载servlet的环境吧
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
//重点关注这个方法
initServletBean();
}
发现其中调用了initServletBean(),发现在HttpServletBean没有具体实现,看他的子类FrameworkServlet,其中得到了webApplicationContext对象,在之前,ContextLoaderListener加载的时候已经创建了WebApplicationContext实例(具体可以查看ContextLoaderListener源码分析),而在这里是对这个实例的进一步补充初始化。这个方法在HttpServletBean的子类FrameworkServlet中得到了重写。
注:ContextLoaderListener载入的是除DispatcherServlet之外的其他的上下文配置文件,而Spring MVC的配置文件是在DispatcherServlet中设置的。
protected final void initServletBean() throws ServletException {
try {
//initWebApplicationContext()来得到webApplicationContext对象
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
}
initFrameworkServlet()是给子类来覆盖的方法,但是我在DispatcherServlet中并没有找到,查看initWebApplicationContext(),还是在FrameWorkServlet中。
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
initWebApplicationContext()方法主要用于创建或刷新WebApplicationContext实例,并对Servlet功能所使用的一些环境变量进行初始化。首先通过findWebApplicationContext()中调用getContextAttribute()来查找ServletContext进行初始化webApplicationContext实例。如果没有,就通过ContextLoaderListener获得的rootContext重新创建一个实例createWebApplicationContext(rootContext)。
protected WebApplicationContext findWebApplicationContext() {
String attrName = getContextAttribute();
if (attrName == null) {
return null;
}
WebApplicationContext wac =
WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
}
return wac;
}
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
"' will try to create custom WebApplicationContext context of class '" +
contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
//这里设置实例的一些参数属性
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}
这些操作都是对webApplicationContext实例的进一步初始化!那么Servlet中配置文件的加载和与rootContext整合是如何进行的?(webApplicationContext是所有Servlet的父环境!),答案是在initWebApplicationContext()中的configureAndRefreshWebApplicationContext()调用的refresh();
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
//这里进行整合,具体的源码就不看了
wac.refresh();
}
那么DisapatcherServlet的初始化是如何进行的?SpringMVC中的组件是如何加载的?答案在initWebApplicationContext()中的onRefresh()方法中,该方法在其子类DispatcherServlet的onRefresh()方法中进行了重写。而在onRefresh()方法中调用了initStrategies()方法来完成初始化工作,初始化Spring MVC的9个组件。
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
initStrategies()完成了对组件的初始化
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
到这就完成了init()的初始化!真累啊。
2.执行过程
当一个get/post请求进来后,会执行sevlet的doPost/doGet方法。以post请求为例。在DispatcherServlet中没有找到,找其父类FrameWorkServlet,发现!
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
调用了processRequest()方法。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
//执行请求
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
查看doService()具体实现在DispatcherServlet中
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
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));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
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()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
其中调用了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对象
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//通过request请求初始化HandlerExecutionChain对象
mappedHandler = getHandler(processedRequest);//重点关注这个方法
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//根据handler选择合适的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()/*这个方法返回的是一个Object handler对象*/);
// 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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//适配器处理handler后返回ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//视图对象的处理
applyDefaultViewName(processedRequest, mv);
//applyPostHandle()该方法会获得拦截器对象数组。HandlerInterceptor[] interceptors = getInterceptors();
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);
}
......
}
doDispatch()做了很多事情,最主要的就是为handler选择相应的处理器适配器(HandlerAdapter)并且处理handler返回ModelAndView对象。最后会渲染视图。
先查看其中的mappedHandler = getHandler()做了那些事情:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
创建了一个处理器映射器(HandlerMapping)对象hm,并且得到了一个处理器执行链(HandlerExecutionChain)对象,(该对象包含了拦截器对象(HandlerInterceptor)和handler对象)。在doDispatch()和下面的getHandler()会体现。
查看其中的hm.getHandler()具体做了那些事!该方法是HandlerMapping接口中的方法。具体实现类AbstractHandlerMapping实现了该方法。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//根据请求获取相应的handler,重点看这里
Object handler = getHandlerInternal(request);
if (handler == null) {
//没有查找到就是用默认的Handler
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
//如果handler是字符串类型 说明是bean名称 需要获取handler bean对象
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//这里封装执行链对象,重点看这里
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
首先具体查看getHandlerInternal()是如何通过request获得handler对象。该方法在AbstractHandlerMapping的子类AbstractHandlerMethodMapping中有实现:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取request中的url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
//根据request中的url来获取HandlerMethod对象(实际就是handler,因为最后返回的就是这个对象)
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
查看lookupHandlerMethod()的具体实现;
// AbstractHandlerMethodMapping
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
//创建匹配集合
List<Match> matches = new ArrayList<>();
// 直接匹配
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
// 存在匹配 则添加到匹配集合中
if (directPathMatches != null) {
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<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
// 排序之后获取第一个
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参数
handleMatch(bestMatch.mapping, lookupPath, request);
// 返回匹配的url处理方法
return bestMatch.handlerMethod;
}
else {
// 处理没有匹配情况直接返回null
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
这样成功匹配到handler对象,接下来在看getHandlerExecutionChain()是如何处理HandlerExecutionChain对象。AbstractHandlerMapping类中。
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);
//遍历拦截器 与当前url匹配的添加至执行链中
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;
}
到这里我们完成了HandlerExecutionHandler对象和其中的Handler对象以及HandlerInterrceptor拦截器对象的初始化,以及获得相应的HandlerAdapter处理器适配器来处理handler对象,然后返回ModelAndView对象上面的都是在DispatcherServlet这个类的doDispatch()方法中进行的!
现在我们还差渲染视图这个工作,也是在doDispatch()中调用的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) {
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.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
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.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
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 + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
到这DispatcherServlet的执行流程基本就结束了。
最后附上基本流程图:
参考:https://blog.csdn.net/qq_38410730/article/details/79426673
https://blog.csdn.net/laravelshao/article/details/82763436
更多推荐
所有评论(0)