目录
3.2 mapping.getHandler(request)是干什么
关于SpringMVC的工作流程,大多数人想必都不太陌生,基本就是前端一个http链接,通过Servlet转发到后端指定的Controller层,找到指定的方法,执行便完了。
那么其具体的细节到底是怎样的,我们通过源码来一步步的进行深究。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//1设置异步线程管理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//2判断是否是一个文件上传请求
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//3获取符合条件的mappedHandler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//4获取HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//5获取ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//6开启异步线程管理
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
1 异步线程管理WebAsyncManager
在看MVC的异步线程管理之前,我们可以粗略的看一看,等了解后面的流程之后再回头看,就会比较清晰。
初略看来就是通过工具类获取了一个WebAsyncManager,然后在执行完ha.handle之后,这个方法就直接返回了。为什么会这样呢?
我们可以看一下ha.handle执行的目的。
2 判断是否是一个文件上传请求
通过this.checkMultipart(request),判断这个servlet请求是否是一个文件上传请求,如果是,需要在后续调用this.cleanupMultipart(processedRequest)
执行清除文件上传的部分属性。
3 获取符合条件的mappedHandler
通过this.getHandler(processedRequest)获取符合条件的mappedHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
通过代码可知,就是通过当前类的handlerMappings迭代循环,根据request参数,找到一个不为null的handler返回即可。那么有两步工作需要搞清楚,
第一步什么是handlerMappings,第二步mapping.getHandler(request)是什么
想要获取mappedHandler,先要了解handlerMappings
3.1 什么是handlerMappings
handlerMappings其实就是接口HandlerMapping实现类的List形式。
public interface HandlerMapping {
String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath";
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
}
可以看到,其核心方法便是getHandler。
那么handlerMappings的值是如何构造的呢?
从DispatcherServlet类中,我们可以看到ioc容器启动的方法:
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
可以看到在容器启动时,会加载一系列的组件,其中就有handlerMappings。
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
其具体方法如下:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
由于this.detectAllHandlerMappings默认为true,所以上面构造handlerMappings的核心方法便是:
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
进入beansOfTypeIncludingAncestors,handlerMappings的构造实现:
public static <T> Map<String, T> beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
Map<String, T> result = new LinkedHashMap(4);
result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory)lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
Map<String, T> parentResult = beansOfTypeIncludingAncestors((ListableBeanFactory)hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
parentResult.forEach((beanName, beanInstance) -> {
if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {
result.put(beanName, beanInstance);
}
});
}
}
return result;
}
总结上面的代码便是,通过ioc的容器中的ListableBeanFactory,根据一系列的条件:HandlerMapping.class、includeNonSingletons、allowEagerInit获取满足条件的HandlerMapping接口的实现类:
{requestMappingHandlerMapping=org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@1077a7, welcomePageHandlerMapping=org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping@3c3d2a80, beanNameHandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@685280dd,
routerFunctionMapping=org.springframework.web.servlet.function.support.RouterFunctionMapping@879f852,
resourceHandlerMapping=org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@792bf78a}
可以看到,返回的都是HandlerMapping的实现类,但不是其实现类的全部。在这里我们需要记住RequestMappingHandlerMapping这个类,也就是我们后续会用到的。
3.2 mapping.getHandler(request)是干什么
说起mapping.getHandler(request)就不得不提起其实现方法,我们通过HandlerMapping接口可以看到,其有一个可以不实现的方法getHandler:
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
通过HandlerMapping的实现类可以看出,仅有一个AbstractHandlerMapping实现了getHandler方法,也就是:
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
通过getHandler的前6行代码和3.1中的代码相结合,我们可以看出,只有返回了不为空的handler,mapping.getHandler(request)这个方法才会返回有效值。
3.2.1 怎么返回不为空的handler
那么怎么返回不为空的handler呢?看RequestMappingHandlerMapping。
Object handler = this.getHandlerInternal(request);
通过RequestMappingHandlerMapping的getHandlerInternal方法,来看是如何取handler的:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
HandlerMethod var2;
try {
var2 = super.getHandlerInternal(request);
} finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
return var2;
}
可以看到是通过父类AbstractHandlerMapping的getHandlerInternal方法来获取的:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//计算出请求路径
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
//设置读锁
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
//根据request参数,找到对应controller层方法
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
//释放锁
this.mappingRegistry.releaseReadLock();
}
return var4;
}
可以看到,getHandlerInternal这个方法就是根据request请求的信息,来找到后台对应controller层的方法。
举个例子,前端请求localhost:8080/test,lookupPath便是解析出/test,然后根据解析出的参数去找对应方法HandlerMethod。
而HandlerMethod这个类中就包含了执行方法的一系列属性,包括beanName,方法注解,方法名称,方法参数等一系列属性,取到之后方便后续操作。
去哪里找呢?在this.lookupHandlerMethod(lookupPath, request)中。
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
//根据路径去集合中查找到所有满足条件的路径集合
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//根据路径集合去找可能满足条件的方法matches
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)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("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
//找到最合适的方法返回
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
在lookupHandlerMethod中,可以详细的看到是如何通过lookupPath的参数来寻找对应的controller层方法的。
其大致意思就是去一个集合中,找到满足lookupPath参数的所有方法,然后再从所有方法中,通过比较,找一个最合适的controller层方法返回。
之后再通过handlerMethod.createWithResolvedBean(),返回真正的执行方法:
public HandlerMethod createWithResolvedBean() {
//controller层的bean名称
Object handler = this.bean;
if (this.bean instanceof String) {
Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
//获取beanName
String beanName = (String)this.bean;
//通过beanName,从ioc容器获取真正的bean
handler = this.beanFactory.getBean(beanName);
}
//构造HandlerMethod
return new HandlerMethod(this, handler);
}
通过createWithResolvedBean,我们又可以反推出,上面的lookupHandlerMethod中返回的HandlerMethod,其实更多的返回的是一种类似于beanDefination的角色,
存储了一些bean和其中指定方法的定义信息,而不是ioc容器中,已经实例化的bean。
3.2.2 为什么别的Mapping不满足
别的怎么会返回空呢?举个例子,BeanNameUrlHandlerMapping的实现:
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
Object handler = this.lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = this.getRootHandler();
}
if (rawHandler == null) {
rawHandler = this.getDefaultHandler();
}
if (rawHandler != null) {
if (rawHandler instanceof String) {
String handlerName = (String)rawHandler;
rawHandler = this.obtainApplicationContext().getBean(handlerName);
}
this.validateHandler(rawHandler, request);
handler = this.buildPathExposingHandler(rawHandler, lookupPath, lookupPath, (Map)null);
}
}
return handler;
}
可以看到关键方法便是Object handler = this.lookupHandler(lookupPath, request):
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
原因便是handlerMap中没有根据urlPath,找到对应的handler,这是由于BeanNameUrlHandlerMapping的作用主要是加载classpatch下面一些默认的url路径。
它的职责定位并不是用来做controller层的转发。
3.2.3 返回HandlerExecutionChain
在找到handler后呢?根据3.2中的代码,还有一步重要工作,那就是根据handler我们可以构造一个HandlerExecutionChain,翻译过来就是方法的执行链。
其作用就是为了对springMVC的请求做一些额外的扩展,比如在进入controller层方法之前,先执行一些拦截器,例如CacheInteceptor,MyBatisInteceptor等等:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
Iterator var5 = this.adaptedInterceptors.iterator();
while(var5.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
可以看到,this.adaptedInterceptors就是在容器初始化的时候会加载一些系统自带,和我们自定义的一些列interceptor,然后再把他们加入到HandlerExecutionChain中。
其原理便在HandlerExecutionChain这个类的定义中:
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
@Nullable
private HandlerInterceptor[] interceptors;
@Nullable
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex;
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[])null);
}
......
可以看到,HandlerExecutionChain其实就是handler和拦截器的一个组合类。
这样就走完了mappedHandler = this.getHandler(processedRequest)中的执行流程,返回了一个带有interceptor集合的HandlerExecutionChain,以后执行方法的时候,就可以其中的interceptor集合先执行一次。
这样就能够对SpringMVC项目做一定的定制。
4 获取HandlerAdapter
在获取到mappedHandler之后呢,下一步便是获取HandlerAdapter:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
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");
}
4.1什么是HandlerAdapter
和第三步处理类似,我们先看下HandlerAdapter的类信息:
public interface HandlerAdapter {
boolean supports(Object var1);
@Nullable
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
比较简单,可以看到,其核心方法应该是执行handle以后返回一个ModelAndView,而我们这一步还没到handle,仅仅是获取到合适的HandlerAdapter实现类就行了。
4.2List<HandlerAdapter>的初始化
和第三步类似,在同一个类中,handlerAdapters也是通过类似的方式初始化,代码就不贴了,得到的实现类如下:
{requestMappingHandlerAdapter=org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@3edc999f, handlerFunctionAdapter=org.springframework.web.servlet.function.support.HandlerFunctionAdapter@670481b2, httpRequestHandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@1e82b631, simpleControllerHandlerAdapter=org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@42c2a1da}
通过第四步的adapter.supports(handler)代码可以看到,基本就是满足某个条件以后返回其中之一的实现类。
4.3获取合适的HandlerAdapter
由于第一个RequestMappingHandlerAdapter的父类AbstractHandlerMethodAdapter,直接就满足了supports方法,所以我们直接就返回了RequestMappingHandlerAdapter
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
private int order = 2147483647;
public AbstractHandlerMethodAdapter() {
super(false);
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return this.order;
}
public final boolean supports(Object handler) {
return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
}
......
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
其实我们可以看到,最后的一个适配器SimpleControllerHandlerAdapter应该也是满足supports方法的,但是它的优先级在后面,所以没有选中。
5 获取ModelAndView
在第四步我们提到了,在获取到合适的适配器以后,我们会执行handle方法,也就是实际的controller层的指定方法,来获取指定的视图和数据。
但是在执行handle之前和之后,会分别执行2个方法:mappedHandler.applyPreHandle(processedRequest, response)和mappedHandler.applyPostHandle(processedRequest, response, mv)。
其实就是取到第三步中返回的HandlerExecutionChain中的interceptors拦截器,分别执行其pre和post方法,来做一些自定义开发。和bean实例化过程中的前置处理器和后置处理器有点类似。
由于第四步中,我们取到的适配器是RequestMappingHandlerAdapter,所以handle的执行便来到了handleInternal中。
由于后面的代码跳跃性比较多,在前面先说一下后面大体的执行逻辑,后面的执行逻辑和前面拦截器的pre和post方法方法有点类似,最重要的三个作用便是:
第一步解析参数:Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs)。
第二步利用cglib代理真正执行方法:this.doInvoke(args)。
第三步处理返回值:this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest)。
其中的第一步和第三步,SpringMVC都提供了一系列的方法可以使用,还可以通过自定义的方式进行增强。
在这里对返回值进行处理的好处是可以直接操作返回对象,而如果等到了handle执行完成之后,打算通过post来处理,会麻烦许多,因为到那个时候数据已经进respond变成了字节流,还需要转换一次。
现在我们开始执行handleInternal:
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
可以看到主要就是为了执行this.invokeHandlerMethod:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndView var15;
try {
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = this.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);
Object result;
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (asyncManager.isConcurrentHandlingStarted()) {
result = null;
return (ModelAndView)result;
}
var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
return var15;
}
主要就是为了执行invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]):
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//第一步和第二步集成方法
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
this.disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
//第三步处理返回数据
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//第一步,获取方法参数
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Arguments: " + Arrays.toString(args));
}
//第二步,执行方法
return this.doInvoke(args);
}
我们的重点在第一步和第三步。
5.1 获取方法参数
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//解析每一个参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (this.logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
解析每一个参数,args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory):
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
} else {
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
重点便在HandlerMethodArgumentResolver这个类中,它有多达几十个实现类,可以来对参数进行解析,包括我们熟悉的@RequestParam注解参数,Pageable,@PathVariable,@ResponseBody等等,都可以进行解析:
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter var1);
@Nullable
Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;
}
可以看到,其实现方法定义和适配器类似,一个方法负责判断该选哪个参数选择器,另外一个方法负责具体的参数解析。
举一个简单的实例:
public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
public PathVariableMapMethodArgumentResolver() {
}
public boolean supportsParameter(MethodParameter parameter) {
PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
return ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(ann.value());
}
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Map<String, String> uriTemplateVars = (Map)webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0);
return !CollectionUtils.isEmpty(uriTemplateVars) ? new LinkedHashMap(uriTemplateVars) : Collections.emptyMap();
}
}
5.2 处理返回数据
通过this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest),我们可以看到如何处理返回数据:
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
和参数解析类似,重点在于HandlerMethodReturnValueHandler这个接口:
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter var1);
void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
}
原理都一样,不再赘述,举个简单例子,我们常用的@RequestBody注解是如何解析返回数据的:
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager) {
super(converters, manager);
}
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable List<Object> requestResponseBodyAdvice) {
super(converters, (ContentNegotiationManager)null, requestResponseBodyAdvice);
}
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {
super(converters, manager, requestResponseBodyAdvice);
}
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
public boolean supportsReturnType(MethodParameter returnType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
}
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return this.adaptArgumentIfNecessary(arg, parameter);
}
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
Object arg = this.readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && this.checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage);
} else {
return arg;
}
}
protected boolean checkRequired(MethodParameter parameter) {
RequestBody requestBody = (RequestBody)parameter.getParameterAnnotation(RequestBody.class);
return requestBody != null && requestBody.required() && !parameter.isOptional();
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
6 开启异步线程管理
走完第五步,基本上SpringMVC的核心流程便已经走完了,这时候如果开启了异步线程,这个请求便直接结束了。
7 小结
了解完springMVC的完整流程,可以更好的对基于springboot框架的项目进行自定义开发,也能更好的理解一个功能为什么要这么做。
比较实际的有,我们可以自定义一系列的拦截器,也了解了它们会在什么时候执行,还可以在进入方法之前对参数和返回值进行自定义处理。
例如笔者就基于参数和返回值的接口,开发出了一套基于JPA的数据权限管理框架。
另外的拦截器的作用,对我们理解一些框架的拦截器也很有帮助,比如SpringCache和Mabtis的一些拦截插件。
最重要的就是,SpringMVC框架中的一些设计思想和设计模式对我们的程序设计有借鉴意义。