目录
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);
- }
- }
- }
在看MVC的异步线程管理之前,我们可以粗略的看一看,等了解后面的流程之后再回头看,就会比较清晰。
初略看来就是通过工具类获取了一个WebAsyncManager,然后在执行完ha.handle之后,这个方法就直接返回了。为什么会这样呢?
我们可以看一下ha.handle执行的目的。
通过this.checkMultipart(request),判断这个servlet请求是否是一个文件上传请求,如果是,需要在后续调用this.cleanupMultipart(processedRequest)
执行清除文件上传的部分属性。
通过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
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
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
进入beansOfTypeIncludingAncestors,handlerMappings的构造实现:
- public static
Map beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { - Assert.notNull(lbf, "ListableBeanFactory must not be null");
- Map
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
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这个类,也就是我们后续会用到的。
说起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)这个方法才会返回有效值。
那么怎么返回不为空的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
.Match> matches = new ArrayList(); - //根据路径去集合中查找到所有满足条件的路径集合
- List
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
.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0); - if (matches.size() > 1) {
- Comparator
.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
.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。
别的怎么会返回空呢?举个例子,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层的转发。
在找到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
interceptorList; - private int interceptorIndex;
-
- public HandlerExecutionChain(Object handler) {
- this(handler, (HandlerInterceptor[])null);
- }
- ......
可以看到,HandlerExecutionChain其实就是handler和拦截器的一个组合类。
这样就走完了mappedHandler = this.getHandler(processedRequest)中的执行流程,返回了一个带有interceptor集合的HandlerExecutionChain,以后执行方法的时候,就可以其中的interceptor集合先执行一次。
这样就能够对SpringMVC项目做一定的定制。
在获取到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");
- }
和第三步处理类似,我们先看下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实现类就行了。
和第三步类似,在同一个类中,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)代码可以看到,基本就是满足某个条件以后返回其中之一的实现类。
由于第一个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方法的,但是它的优先级在后面,所以没有选中。
在第四步我们提到了,在获取到合适的适配器以后,我们会执行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);
- }
我们的重点在第一步和第三步。
- 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
uriTemplateVars = (Map)webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0); - return !CollectionUtils.isEmpty(uriTemplateVars) ? new LinkedHashMap(uriTemplateVars) : Collections.emptyMap();
- }
- }
通过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
> converters) { - super(converters);
- }
- public RequestResponseBodyMethodProcessor(List
> converters, @Nullable ContentNegotiationManager manager) { - super(converters, manager);
- }
- public RequestResponseBodyMethodProcessor(List
> converters, @Nullable List { - super(converters, (ContentNegotiationManager)null, requestResponseBodyAdvice);
- }
- public RequestResponseBodyMethodProcessor(List
> converters, @Nullable ContentNegotiationManager manager, @Nullable List { - 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
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);
- }
- }
走完第五步,基本上SpringMVC的核心流程便已经走完了,这时候如果开启了异步线程,这个请求便直接结束了。
了解完springMVC的完整流程,可以更好的对基于springboot框架的项目进行自定义开发,也能更好的理解一个功能为什么要这么做。
比较实际的有,我们可以自定义一系列的拦截器,也了解了它们会在什么时候执行,还可以在进入方法之前对参数和返回值进行自定义处理。
例如笔者就基于参数和返回值的接口,开发出了一套基于JPA的数据权限管理框架。
另外的拦截器的作用,对我们理解一些框架的拦截器也很有帮助,比如SpringCache和Mabtis的一些拦截插件。
最重要的就是,SpringMVC框架中的一些设计思想和设计模式对我们的程序设计有借鉴意义。