Spring MVC 执行原理
通过跟进源码,整理了一些spring mvc 的运行流程,及一些自认为重要的代码片段,以记录为主,顺便分享一下。
Spring MVC 流程简述
首先是Spring Mvc的执行流程图
主要步骤
FrameworkServlet继承了HttpServlet
http请求发送到FrameworkServlet的doService方法,实现类是DispatcherServlet
- http请求到调度器servlet--DispatcherServlet;
- DispatcherServlet收到请求调用HandlerMapping处理映射器;
- 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
- DispatcherServlet调用HandlerAdapter处理适配器;
- HandlerAdapter转发到具体的Controller方法;
- Controller执行完成返回ModelAndView
- HandlerAdapter将结果转到DiapatcherServlet;
- DispatcherServlet将model转到ViewResolver视图解析器;
- ViewReslover解析后返回具体View;
- DispatcherServler响应用户
详情
有兴趣的,来看我啰嗦一会
首先看一下工作时间最长的DispatcherServlet,简单了解一下它的功能
DispatcherServlet类和继承关系
org.springframework.web.servlet.DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {..}
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {...}
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {...}
关系图如下
现在开始步入正题
1 http请求到DispatcherServlet的doService方法
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {...}
这是spring mvc的入口,spring mvc公开此方法,用于之后的调度。
此方法的部分代码:
// 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());
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);
}
此代码是补充一些数据,后续的程序需要用到的一些数据;
数据的结构如图所示:
接下来就是核心代码了
doDispatch(request, response);
doDisPatch的注释已经把流程讲清楚了
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {...}
所有的HTTP 请求都将这样处理::程序获取HandlerMappings和HandlerAdapters的第一个实现对象
2 DispatcherServlet收到请求调用HandlerMapping处理映射器
这一步的目的是获取HandlerMethod,其中包含请求对应的Controller及目标方法的信息
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
getHandler方法实现:取第一个实现的对象
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
...
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
实现类:
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {...}
实现方法:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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 (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
具体获取MappingHandler的操作:
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
lookupPath是请求的路径,根据url获取对应的RequestMapping
每一个url都有对应的RequestMappingInfo对象,如图:
接下来是获取handlerMethod
获取到RequestMappingInfo对象后,调用方法,拼装Match,会从RequestMappingInfo中解析到handler信息拼到match中,目的是获取到hradlerMethod;
addMatchingMappings(directPathMatches, matches, request);
在此可以获取到url对应的Controller和对应的方法;
之后将HandlerMethod返回出去,获取HandlerMethod是此方法执行的主要目的;
其中,url对应的mapping信息来自于项目配置的xml文件或代码中的Controller相关注解;
3 DispatcherServlet调用HandlerAdapter处理适配器
此次目的是先要获取到一个HandlerAdapter;
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
用获取到的handler信息,来获取HandlerAdapter,mappedHandler.getHandler()---就是之前获取的HandlerMathod;
方法实现:
/**
* Return the HandlerAdapter for this handler object.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
HandlerAdapter有以下几个实现类:
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {...}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {...}
class CompositeHandlerAdapter implements HandlerAdapter {...}
public class HttpRequestHandlerAdapter implements HandlerAdapter {...}
public class SimpleControllerHandlerAdapter implements HandlerAdapter {...}
public class SimpleServletHandlerAdapter implements HandlerAdapter {...}
这里的关键方法ha.supports(handler)的实现有点过分简陋了,来这里寻找HandlerAdapter对象,简直就是白给的。
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
这里获取的HandlerAdapter是RequestMappingHandlerAdapter。
4 HandlerAdapter转发到具体的Controller方法
HandlerAdapter的目的是获取业务处理的结果,并将其封装成统一的ModelAndView
ModelAndView mv = null;
.......
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这个就是调用Controller方法,并将处理结果转成ModelAndView;
方法实现:
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
这里有用到synchronized 来控制一个session里的请求必须是串行的,也就是单个spring mvc节点下,一个用户的请求不允许并发;
这里的请求都转到了invokeHandlerMethod方法执行
mav = invokeHandlerMethod(request, response, handlerMethod);
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = 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()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
核心动作就是这个,执行方法
ServletInvocableHandlerMethod invocableMethod = new ServletInvocableHandlerMethod(handlerMethod);
invocableMethod.invokeAndHandle(webRequest, mavContainer);
此方法最终动作也就是调用反射的invoke方法,执行Controller的调用
public class InvocableHandlerMethod extends HandlerMethod {
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
return getBridgedMethod().invoke(getBean(), args);
...
}
}
下一步就是到了Controller方法里,这是笔者自己写的Controller方法,经过一大波的折腾,就是为了执行这段代码。
@RequestMapping(path = "/bwhealth")
public String health() {
return "SUCCESS";
}
5 Controller执行完成返回ModelAndView
将Controller结果转换成modelAndView的代码还是这个
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) {
throw ex;
}
}
主要是一些空判断处理等逻辑,核心代码就这一句转发
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
实现就是对ModelAndViewContainer对象的数据进行拼装,获得到ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
6 将http结果响应出去
接下来就是将ModelAndView的数据,发送到请求端,只是通过以下代码执行
((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage);
....
public final void write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
final HttpHeaders headers = outputMessage.getHeaders();
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
@Override
public OutputStream getBody() {
return outputStream;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}));
}
else {
writeInternal(t, outputMessage);
outputMessage.getBody().flush();
}
}
到此,请求方就收到了接口的响应结果
当然至此,代码还有一段路要走,就不再跟了。
这就是一个http请求进入spring mvc到出去的一些步骤,当然,事无巨细,还有很多细节没有展现出来,有兴趣的就自己跟一下源码看看吧。这会让你感觉,这么高大上的框架,实现起来也是这么的接地气,只不过是对一些基本操作的封装罢了。