SpringMVC系列(一)执行流程

本系列结合源码(基于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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SpringMVC是一种基于MVC架构的Web框架,其执行流程大致如下: 1. 客户端向服务器发送请求,请求到达DispatcherServlet。 2. DispatcherServletSpringMVC框架的核心,它负责接收所有请求并将其分发给对应的处理器(Controller)。 3. HandlerMapping负责将请求映射到对应的处理器(Controller)。 4. Controller接收到请求后进行处理,并返回一个ModelAndView对象。 5. ViewResolver负责将返回的ModelAndView对象解析为对应的视图(View)。 6. 视图(View)生成响应,返回给DispatcherServlet。 7. DispatcherServlet将响应发送给客户端。 整个过程中,通过使用拦截器(Interceptor)可以对请求进行预处理和后处理,同时也可以通过适当的配置将一些处理过程进行缓存,提高处理效率。 ### 回答2: Spring MVC是一个用于开发Web应用程序的框架,其执行流程如下: 1. 客户端发送请求到DispatcherServlet(前端控制器)。 2. DispatcherServlet根据请求的URL映射到对应的处理器映射器(HandlerMapping)。 3. 处理器映射器根据URL映射到对应的处理器(Controller)。 4. 处理器开始处理请求,执行业务逻辑处理操作。 5. 处理器将处理结果封装成ModelAndView对象。 6. 处理器返回ModelAndView对象给DispatcherServlet。 7. DispatcherServlet调用视图解析器(ViewResolver)来解析ModelAndView对象中的视图名,得到具体的视图对象。 8. 视图对象负责渲染视图,并返回给DispatcherServlet。 9. DispatcherServlet将渲染后的视图返回给客户端。 10. 客户端收到响应,呈现出用户界面。 以上是Spring MVC的大致执行流程,通过DispatcherServlet作为中央控制器来分发请求并协调各个组件的工作,实现了请求和处理的分离,使得代码结构清晰、易于维护。同时,通过统一的编程模型和灵活的扩展机制,Spring MVC可以满足各种不同的Web开发需求。 ### 回答3: SpringMVC是一个基于MVC设计模式的Web开发框架,其执行流程可以简单概括为以下几个步骤: 1. 用户发送请求:当用户在浏览器中访问某个URL时,请求首先发送到DispatcherServlet,它是整个SpringMVC的控制中心。 2. 请求映射:DispatcherServlet根据请求的URL,通过HandlerMapping来确定要调用的Controller类。 3. 控制器处理:Controller类根据具体的业务逻辑进行处理,并返回相应的结果。 4. 模型数据处理:Controller处理完成后,会将结果封装到Model对象中,Model对象是对请求结果的封装。 5. 视图解析:DispatcherServlet根据返回的Model对象和视图解析器(ViewResolver)来确定要返回的视图。 6. 视图渲染:将视图模板和Model对象结合,渲染出最终的视图。 7. 响应返回:DispatcherServlet将最终的视图返回给用户的浏览器,请求响应完成。 在SpringMVC中,有一系列的组件负责各个步骤的处理,如HandlerMapping负责请求映射,HandlerAdapter负责控制器处理,ViewResolver负责视图解析等。通过这些组件的协作,实现了请求的转发和处理,使得开发者可以专注于具体的业务逻辑实现而无需关注底层的请求处理细节。 总结起来,SpringMVC执行流程是:请求发送到DispatcherServlet -> 请求映射 -> 控制器处理 -> 模型数据处理 -> 视图解析 -> 视图渲染 -> 响应返回。通过这个流程,可以实现灵活可扩展的Web应用程序开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值