SpringMVC的核心流程
-
建立请求和Controller方法的映射集合的流程。
-
根据请求查找对应的Controller方法的流程。
-
请求参数绑定到方法形参,执行方法处理请求,返回结果进行视图渲染的流程。
HandlerMapping
HandlerMapping接口作用是将请求映射到处理程序,以及预处理和处理后的拦截器列表,映射是基于一些标准的,其中的细节因不同的实现而不相同。这是官方文档上一段描述,该接口只有一个方法getHandler(request),返回一个HandlerExecutionChain对象,接口本身很简单。
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"; // 返回请求的一个处理程序handler和拦截器interceptors @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }DispatcherServlet
DispatcherServlet是Spring MVC核心,它是J2EE规范前端控制器的实现,负责拦截用户请求,并解析请求进行转发。
public class DispatcherServlet extends FrameworkServlet { @Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { //初始化文件上传处理器 initMultipartResolver(context); //初始化国际化配置 initLocaleResolver(context); //初始化主题处理器 initThemeResolver(context); //初始化HanlderMapping initHandlerMappings(context); //初始化HandlerAdapter //HandlerAdapter用来调用具体的方法对用户发来的请求来进行处理 initHandlerAdapters(context); //初始化异常处理器, // HandlerExceptionResolver是用来对请求处理过程中产生的异常进行处理 initHandlerExceptionResolvers(context); //RequestToViewNameTranslator用于在视图路径为空的时候,自动解析请求 //去获取ViewName initRequestToViewNameTranslator(context); //初始化视图处理器 //ViewResolvers将逻辑视图转成view对象 initViewResolvers(context); //FlashMapManager用于存储、获取以及管理FlashMap实例 initFlashMapManager(context); } }从方法调用链看,DispatcherServlet的initStrategies方法是在OnRefresh方法之后调用的,而initHandlerMappings方法是在initStrategies方法中被调用的。
initHandlerMappings
- 初始化HanlderMapping
这就是HanlderMapping的初始化过程。
HandlerMapping的实现类
从方法调用链可以得知,SpringMvc有四种HandlerMapping:
- requestMappingHandlerMapping -> RequestMappingHandlerMapping
- beanNameHandlerMapping -> BeanNameUrlHandlerMapping
- routerFunctionMapping -> RouterFunctionMapping
- defaultServletHandlerMapping -> SimpleUrlHandlerMapping
这里主要关注RequestMappingHandlerMapping
-
由于RequestMappingHandlerMapping实现了ApplicationContextAware和ServletContextAware两个接口,这说明RequestMappingHandlerMapping可以通过这两个接口获取到Root容器和Servley子容器中的Bean。
-
RequestMappingHandlerMapping还实现了InitializingBean接口,该接口的afterPropertiesSet方法是在bean初始化的invokeInitMethods方法之后执行的,因此可以在这里加入对标记有RequestMapping标记的Bean进行处理,将相关的映射关系依次保存到RequestMappingHandlerMapping或者其父类的成员变量里面。
AbstractHandlerMethodMapping
在类图中AbstractHandlerMethodMapping实现了InitializingBean接口,重写了afterPropertiesSet方法
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { @Override public void afterPropertiesSet() { initHandlerMethods(); } }从方法调用链可以看出:
-
程序在Bean初始化后,会立即执行AbstractHandlerMethodMapping中的afterPropertiesSet方法,这是因为RequestMappingHandlerMapping是需要先在容器中创建出来,后续才能在DispatcherServlet中的initHandlerMappings方法中去作为HandlerMapping的实现类给载入到DispatcherServlet的成员变量handlerMappings集合里。
-
又因为RequestMappingHandlerMapping在创建的时候会去调用invokeInitMethods方法进行初始化,也会执行afterPropertiesSet里面的逻辑,也就是会先执行initHandlerMethods的逻辑去初始化映射关系。
AbstractHandlerMethodMapping#initHandlerMethods
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { protected void initHandlerMethods() { //遍历容器里所有的Bean for (String beanName : getCandidateBeanNames()) { //忽略掉scopedTarget.打头的bean(session application request之类的作用域内的代理类) if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } protected String[] getCandidateBeanNames() { //从root容器以及子容器里,或者仅从子容器里获取所有的Bean return (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); } }- 根据detectHandlerMethodsInAncestorContexts变量是否为true,来决定是否需要从root容器以及子容器里,或者仅从子容器里获取所有的Bean。
- 如果为false,则只从当前的子容器即ServletContext里去查找。
- 而如果Root容器中有bean被标记上RequestMapping的话,detectHandlerMethodsInAncestorContexts就会被标记为true。
AbstractHandlerMethodMapping#processCandidateBean
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { //获取Bean的Class类型 beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } //判断Class上是否有Controller注解或是RequestMapping注解 if (beanType != null && isHandler(beanType)) { //提取其url与controller映射关系 detectHandlerMethods(beanName); } } } public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping, EmbeddedValueResolverAware { @Override protected boolean isHandler(Class<?> beanType) { //判断类上是否存在Controller注解或是RequestMapping注解 return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } }- 首先获取Bean对应的Class对象。
- 通过判断Class上是否有Controller注解或是RequestMapping注解,为后续提取其url与controller映射关系做好准备。
AbstractHandlerMethodMapping#detectHandlerMethods
- 发觉Controller方法,并建立与请求url的映射关系。
RequestMappingHandlerMapping#getMappingForMethod
- 创建求映射信息对象RequestMappingInfo。
视线拉回到detectHandlerMethods方法中:
-
在执行完AbstractHandlerMethodMapping类中的detectHandlerMethods方法中的selectMethods方法之后,就能建立起Controller方法实例和RequestMappingInfo的映射关系,并将相关的映射保存到methods这个Map<Method, T>集合中,key为方法实例,value为RequestMappingInfo实例。
-
之后会遍历methods将相关的映射信息给注册到HandlerMapping中。
上面这段代码,会将methods中的Method实例和RequestMappingInfo实例给一一对应的注册到HandlerMapping里面。
AbstractHandlerMethodMapping#registerHandlerMethod
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } class MappingRegistry { //储存 MappingRegistration 所有的注册信息 private final Map<T, MappingRegistration<T>> registry = new HashMap<>(); //储存RequestMappingInfo 与 HandlerMethod private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>(); //储存路径与RequestMappingInfo private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>(); //储存@RequestMapping 注解的请求路径 与 HandlerMethod列表 private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>(); //跨域配置 private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>(); //读写锁 private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); /** * 注册数据: mapping => RequestMappingInfo || handler => beanName || method => Method * 1、根据 handle 和 method,创建 HandlerMethod, * 2、效验 HandlerMethod 是否存在 * 3、储存 HandlerMethod * 4、储存 RequestMappingInfo 跟 url * 5、储存 @RequestMapping 注解 的路径跟所有的方法 * 6、存储 CorsConfiguration 信息(跨域) * 7、储存 MappingRegistration 对象 */ public void register(T mapping, Object handler, Method method) { // Assert that the handler method is not a suspending one. if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { Class<?>[] parameterTypes = method.getParameterTypes(); if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) { throw new IllegalStateException("Unsupported suspending handler method detected: " + method); } } this.readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); //验证方法的唯一性,即先前是否已经注册过同样的映射 validateMethodMapping(handlerMethod, mapping); //注册RequestMappingInfo 和 HandlerMethod this.mappingLookup.put(mapping, handlerMethod); //注册请求路径与对应的RequestMappingInfo List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { this.urlLookup.add(url, mapping); } String name = null; if (getNamingStrategy() != null) { //注册请求路径与HandlerMethod name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { //注册HandlerMethod与跨域信息 this.corsLookup.put(handlerMethod, corsConfig); } //创建及注册 MappingRegistation 信息 this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } } } }主要步骤:
- 1、根据 handle 和 method,创建 HandlerMethod,
- 2、效验 HandlerMethod 是否存在,验证方法的唯一性,即先前是否已经注册过同样的映射
- 3、注册RequestMappingInfo 和 HandlerMethod
- 4、注册请求路径与对应的RequestMappingInfo
- 5、注册请求路径与HandlerMethod
- 6、注册HandlerMethod与跨域信息
- 7、创建及注册 MappingRegistation 信息
最终会将前面获取到的所有信息给包装起来,保存到Map<T, MappingRegistration<T>> registry成员变量中,后续就可以解析请求并选择合适的Controller方法来对请求进行处理。
这样就完成了建立请求和Controller方法的映射集合的流程的分析。
HandlerAdapter
public interface HandlerAdapter { //判断适配器是否适配handler,适配策略由子类实现 boolean supports(Object handler); //使用适配的handler执行用户请求 @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //返回资源的最后修改时间,如果handler实现类不支持可以返回-1 long getLastModified(HttpServletRequest request, Object handler); }以上是HandlerAdapter接口的源码分析,如需自定义HandlerAdapter,只需要实现该接口,在supports方法中定义适配策略,并实现handle方法进行调用即可。
HandlerAdapter的初始化
顾名思义,是handler的适配器,它能处理参数转换为handler能接受的数据类型,解析参数、处理返回值等。
在DispatcherServlet进行初始化流程调用initStrategies,执行完initHandlerMappings方法后,会接着执行initHandlerAdapters方法。
initHandlerAdapters
- 初始化HandlerAdapter
通过initHandlerAdapters方法的调用栈可知,一共向List<HandlerAdapter> handlerAdapters集合中注册了4个HandlerAdapter的实现类。
-
requestMappingHandlerAdapter -> RequestMappingHandlerAdapter
-
handlerFunctionAdapter -> HandlerFunctionAdapter
-
httpRequestHandlerAdapter -> HttpRequestHandlerAdapter
-
simpleControllerHandlerAdapter -> SimpleControllerHandlerAdapter
以上就是Spring MVC对HandlerAdapter组件的注册过程。
参考: https://segmentfault.com/a/1190000014901736
https://segmentfault.com/a/1190000015009343
https://segmentfault.com/a/1190000015027885