Spring mvc分析
前置知识
在阅读此文章前, 了解一下基础知识有助于阅读
Spring bean
的生命周期
ApplicationContext
的创建流程
Servlet
相关知识
Tomcat
的简单配置和使用
环境搭建
添加依赖
spring mvc
tomcat-embed-core
配置类
1 2 3 4 5
| @EnableWebMvc @ComponentScan @Configuration public class Config { }
|
启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class TomcatServer { private static final int PORT = 8080; private static final String CONTEXT_PATH = "/web";
public static void main(String[] args) throws Exception { Tomcat tomcatServer = new Tomcat(); tomcatServer.setPort(PORT);
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(Config.class); DispatcherServlet dispatcherServlet = new DispatcherServlet(context); Wrapper servlet = tomcatServer. addServlet(CONTEXT_PATH, "DispatcherServlet", dispatcherServlet); servlet.addMapping("/*");
tomcatServer.start(); System.out.println("Tomcat started"); tomcatServer.getServer().await();
} }
|
流程图
spring-mvc
的整个流程大致如下图所示:
DispatcherServlet
是整个流程的中心, 也是mvc的核心组件
图片来自网络
DispatcherServlet
DispatcherServlet
继承的类和实现的接口
1 2 3
| public class DispatcherServlet extends FrameworkServlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
|
DispatcherServlet
实现了Servlet
接口, 了解过Servlet
的同学都知道, Tomcat
会通过servlet-mapping
加载匹配当前url
的Servlet
对象. 调用doService
方法处理请求
setApplicationContext
如果使用的是springboot项目:
FrameworkServlet
实现了ApplicationContextAware
接口, 所以在bean初始化的时候会传入ApplicationContext
,
使用springboot
启动, 则该类的具体实现为AnnotationConfigServletWebServerApplicationContext
1 2 3 4 5 6 7
| @Override public void setApplicationContext(ApplicationContext applicationContext) { if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) { this.webApplicationContext = (WebApplicationContext) applicationContext; this.webApplicationContextInjected = true; } }
|
static
在spring-webmvc
的resources目录下面有个DispatcherServlet.properties
文配置件, 里面是strategy interfaces的默认实现类, DispatcherServlet
在静态代码块里面加载这个配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| static { try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { ... } }
|
init
DispatcherServlet
也是一个Servlet
, Tomcat
会调用每一个Servlet
的初始方法先进行初始化, 然后再调用doService
方法处理请求
父类HttpServletBean
的初始方法
1 2 3 4 5 6 7
| public final void init() throws ServletException { ... initServletBean(); }
|
往下走到FrameworkServlet
的initServletBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Override protected final void initServletBean() throws ServletException { ... try { this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); } catch (ServletException | RuntimeException ex) { logger.error("Context initialization failed", ex); throw ex; }
... }
|
继续往下走到initWebApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null;
if (this.webApplicationContext != null) { wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { if (cwac.getParent() == null) { cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { wac = findWebApplicationContext(); } if (wac == null) { wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { synchronized (this.onRefreshMonitor) { onRefresh(wac); } }
if (this.publishContext) { String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); }
return wac; }
|
来到 configureAndRefreshWebApplicationContext
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { ... wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); wac.addApplicationListener( new SourceFilteringListener(wac, new ContextRefreshListener()));
ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env). initPropertySources(getServletContext(), getServletConfig()); } postProcessWebApplicationContext(wac); applyInitializers(wac); wac.refresh(); }
|
到此context初始化方法就差不多了, 然后就是初始化spring mvc需要的一些组件
ContextRefreshListener
当WebApplicationContext
完成刷新之后, context会发布一个context刷新完成事件, 该Listener
就可以获取到这事件调用onApplicationEvent
进行处理
1 2 3 4 5 6 7
| private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override public void onApplicationEvent(ContextRefreshedEvent event) { FrameworkServlet.this.onApplicationEvent(event); } }
|
接下来进入到FrameworkServlet
的onApplicationEvent
方法
1 2 3 4 5 6 7
| public void onApplicationEvent(ContextRefreshedEvent event) { this.refreshEventReceived = true; synchronized (this.onRefreshMonitor) { onRefresh(event.getApplicationContext()); } }
|
继续进入onRefresh
方法, 在DispatcherServlet
类中
1 2 3
| protected void onRefresh(ApplicationContext context) { initStrategies(context); }
|
进入initStrategies
, 里有很多的初始化方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
|
到这里之后, spring mvc的初始化大致就完成了, 接下来就是处理请求了
doService
用curl
发送一个请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request);
...
try { doDispatch(request, response); } finally { ... } }
|
doDispatch
进入doDispatch方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ...
try { ModelAndView mv = null; Exception dispatchException = null;
try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request);
mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; }
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; }
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } ... processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { ... } ... }
|
getHandler
接下来我们进入getHandler
方法, 该方法会遍历mapping, 返回处理器链
1 2 3 4 5 6 7 8 9 10 11 12
| @Nullable 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; }
|
我们再进入AbstractHandlerMapping
看一下handler是如何获取到的
1 2 3 4 5
| public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); ... return executionChain; }
|
getHandlerInternal
进入getHandlerInternal
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); request.setAttribute(LOOKUP_PATH, lookupPath); this.mappingRegistry.acquireReadLock(); try { HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }
|
在lookupHandlerMethod
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| @Nullable 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()) { addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); }
if (!matches.isEmpty()) { Match bestMatch = matches.get(0); if (matches.size() > 1) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); bestMatch = matches.get(0); if (logger.isTraceEnabled()) { logger.trace(matches.size() + " matching mappings: " + matches); } 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(); String uri = request.getRequestURI(); throw new IllegalStateException ... } } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } }
|
getHandlerAdapter
getHandlerAdapter
获取handler
的适配器, 通过适配器调用handler
1 2 3 4 5 6 7 8 9 10 11 12
| 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... }
|
adapter.handle
调用handler, 来到一个AbstractHandlerMethodAdapter
抽象类中
1 2 3 4 5
| public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
|
handleInternal
handleInternal
由子类RequestMappingHandlerAdapter
实现,这也是springmvc默认的adapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav; checkRequest(request);
if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); }
...
return mav; }
|
invokeHandlerMethod
接下来进入invokeHandlerMethod
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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); ... invocableMethod.invokeAndHandle(webRequest, mavContainer); ...
return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
|
invokeAndHandle
接着进入到invocableMethod.invokeAndHandle
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest);
... try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { ... } }
|
invokeAndHandle
invokeAndHandle
中
1 2 3 4 5 6 7 8 9 10
| public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); }
|
doInvoke
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Nullable protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { ... } catch (InvocationTargetException ex) { ... } }
|
handleReturnValue
位于: RequestResponseBodyMethodProcessor
调用完成之后, 得到返回值, springmvc就处理返回值, 返回给客户端
1 2 3 4 5 6 7 8 9 10 11
| @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException... } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
|
来到handleReturnValue
方法中
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
|
writeWithMessageConverters
这里主要是通过springmvc
中的converts
来处理方法的返回值, 并写到response
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object body; Class<?> valueType; Type targetType;
if (value instanceof CharSequence) { body = value.toString(); valueType = String.class; targetType = String.class; } else { body = value; valueType = getReturnValueType(body, returnType); targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass()); }
...
MediaType selectedMediaType = null; MediaType contentType = outputMessage.getHeaders().getContentType(); boolean isContentTypePreset = contentType != null && contentType.isConcrete(); if (isContentTypePreset) { ... selectedMediaType = contentType; } else { ... if (mediaTypesToUse.isEmpty()) { if (body != null) { throw new HttpMediaTypeNotAcceptableException(producibleTypes); } if (logger.isDebugEnabled()) { ... } return; }
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
for (MediaType mediaType : mediaTypesToUse) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } ... }
if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> converter : this.messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice(). beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage); if (body != null) { Object theBody = body; ... addContentDispositionHeader(inputMessage, outputMessage); if (genericConverter != null) { genericConverter.write(body, targetType, selectedMediaType, outputMessage); } else { ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage); } } else { if (logger.isDebugEnabled()) { ... } } return; } } }
if (body != null) { ... throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); } }
|
结尾
到此, springmvc
的大致流程就结束了, 本篇文章就只是大致的说明了一下spring-mvc
启动到处理请求的流程,spring-mvc
中还有很多细节需要我们慢慢去看源码.
声明