springMvc - Mapping匹配过程
2019-08-22 19:52:07 32 举报
AI智能生成
SpringMVC请求过程,当一个请求传来时,Spring都做了什么
作者其他创作
大纲/内容
springMVC
1. 扫描controller注解和requstMapping注解的类初始化成handlerMethod
HttpServletBean.init将配置参数映射到此servlet的bean属性,并调用子类初始化。FrameworkServlet.initServletBeanFrameworkServlet.initWebApplicationContext初始化WebApplicationContextFrameworkServlet.createWebApplicationContext创建WebApplicationContextFrameworkServlet.configureAndRefreshWebApplicationContextfont color=\"#c41230\
AbstractHandlerMethodMapping.initHandlerMethods扫描ApplicationContext中的bean,检测和注册处理程序方法。font color=\"#c41230\
获取所有beanNames放入数组font color=\"#c41230\
从findAnnotationCacheMap中获取该bean和controller注解
1. clazz.getDeclaredAnnotations()常规的获取注解的方法
detectHandlerMethods在处理程序中寻找处理程序方法。
1. 获取handler的Class对象(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()比如此处获取的是GameController
3. registerHandlerMethod遍历GameController下的全部方法来调用该方法注册到HandlerMethodMapping中
HandlerMethod
private final Object bean;
private final BeanFactory beanFactory; 该bean的工厂
private final Class<?> beanType; controller
private final Method method; 请求路径对应的方法
this.bridgedMethod = handlerMethod.bridgedMethod;
private final MethodParameter[] parameters;
将该方法处理器类放入名为handlerMethods的Map中
key : requestMappingInfo
value : HandlerMethod类
将请求路径放入urlMap中
key : Set<String>类型的请求路径
value : requestMappingInfo
封装以下请求映射条件
匹配方式 : Patterns
请求方法 : method
请求参数 : params
url请求头 : headers
Consumes
Produces
updateNameMap将方法处理器放入nameMap中
key : GC#方法名
value : HandlerMethod类
getHandlerMethods
handlerMethodsInitialized
2. 初始化handlerMapping
DispatcherServlet.initStrategies初始化该servlet使用的策略对象
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);初始化该类使用的HandlerMappings。如果在BeanFactory中没有为这个名称空间定义HandlerMapping bean,我们默认为BeanNameUrlHandlerMapping。
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
3. 拦截分发前端请求
FrameworkServlet.service
获取请求方式 get/post/patch等
patch进入FrameworkServlet.processRequest
否则进入httpServlet.service
根据请求方式调用相应方法.如doGet
拦截请求
4. 根据请求查找对应的handlerMethod并返回ModelAndView
例如 : 调用FrameworkServlet.doGet
DispatcherServlet.doService
checkMultipart(request); 处理是否是文件上传请求
DispatcherServlet.getHandler返回的是一个HandlerExecutionChain(执行链)font color=\"#c41230\
根据请求获取对应方法和类
1. 遍历handlerMappings
1. RequestMappingHandlerMapping
2. BeanNameUrlHandlerMaping
3. SimpleUrlHandlerMapping
AbstractHandlerMapping.getHandler查询请求的处理器执行链
1. AbstractHandlerMethodMapping.getHandlerInternal 查找给定请求的处理程序方法。返回HandlerMethod类
getUrlPathHelper 用于URL路径匹配的Helper类。提供对RequestDispatcher include中的URL路径的支持,并支持一致的URL解码。
getLookupPathForRequest
getPathWithinServletMapping(request)返回给定请求的servlet映射中的路径,从request获取到/game/games.do请求路径
getPathWithinApplication(request)返回给定请求的web应用程序内的路径。/game/games.do
getContextPath : 获取请求根目录/myjava
getRequestUri : 获取请求路径 (request.getRequestURI())
decodeAndCleanUriString : 解码提供的URI字符串,并去除';'后面的任何无关部分。
getRemainingPath : 去除掉请求路径中的项目名称等
getServletPath(request)request.getServletPath()返回servlet请求路径 /game/games.do
getRemainingPath
lookupHandlerMethod 查找当前请求的最佳匹配处理程序方法。如果找到多个匹配项,则选择最佳匹配项。也就是根据上一步获取的路径找到最佳匹配的包装了Controller的HandlerMethod
根据key /game/games.do 从urlMap中获取直接匹配
urlMap中存的是全部的requestMapping地址
getMatchingMapping遍历获取urlMap的匹配结果来调用此方法
private final T mapping;
private final HandlerMethod handlerMethod;
添加Match进集合 matches
RequestMappingInfoHandlerMapping.handleMatch向request中set一些参数
return HandlerMethod.createWithResolvedBean返回一个新的保存了controller的HandlerMethod
return new HandlerMethod
添加拦截器.font color=\"#c41230\
DispatcherServlet.getHandlerAdapter返回适配的处理器
遍历handlerAdapters
1. RequestMappingHandlerAdapter
2. HttpRequestHandlerAdapter
3. SimpleControllerHandlerAdapter
handlerAdapters.supports(handler)
supportsInternal(handler)
AbstracthandlerAdaptersget.LastModified
getLastModifiedInternal : 总是返回-1
AbstractHandlerMethodAdapter.handle使用HandlerAdapter来执行handleri style=\
RequestMappingHandlerAdapter.handleInternal
checkAndPrepare
applyCacheSeconds
invokeHandleMethod返回ModelAndView
创建一个ServletWebRequest
getDataBinderFactory创建 WebDataBinderFactory
判断是否初始化过
createDataBinderFactory
getWebBindingInitializer
new ServletRequestDataBinderFactory
getModelFactory创建ModelFactory
与getDataBinderFactory类似
createRequestMappingMethod创建ServletInvocableHandlerMethod
new 一个 ServletInvocableHandlerMethod
initResponseStatus判断是否有responseStatus注解
setHandlerMethodArgumentResolvers 等属性
new ModelAndViewContainer创建ModelAndView容器
modelFactory.initModel初始化model
invokeModelAttributeMethods调用模型属性方法来填充模型。
ServletInvocableHandlerMethod.invokeAndHandle这里开始绑定参数和调用我们开发的方法
InvocableHandlerMethod.invokeForRequestfont color=\"#c41230\
InvocableHandlerMethod.getMethodArgumentValues获取当前请求的方法参数值。font color=\"#c41230\
getMethodParameters调用handlerMethod的parameters参数?????什么时候放进去的???????
是一个MethodParameter类
MethodParameter是属于哪一个HandlerMthod类
method : 参数所在的方法
parameterType : 参数类型
获取请求参数
遍历参数用于绑定
this.argumentResolvers.supportsParameter(parameter)判断注册的方法是否支持指定的参数从argumentResolver中获取
getArgumentResolver(parameter)
获取方法中的形参类型并创建实例
ModelFactory.getNameForParameter(parameter);
ModelFactory.getNameForParameter(parameter);获取参数名称game
annot = parameter.getParameterAnnotation(ModelAttribute.class);判断字段是否被ModelAttribute注解
若未被注解则使用Conventions.getVariableNameForParameter取值
判断是否是数组
否则直接取参数的类型
binderFactory.createBinder开始将参数值绑定到对象中
initBinder初始化绑定器
set一些值
this.bean = handler; bean = controller\t\tthis.parameters = handlerMethod.parameters;
this.beanFactory = handlerMethod.beanFactory; 该bean的工厂
this.beanType = handlerMethod.beanType; controller
this.method = handlerMethod.method; 请求路径对应的方法
ServletModelAttributeMethodProcessor.bindRequestParameters绑定实参到这里结束我们binder属性中的target对象的gameId的值变为了1
获取servletRequest
将绑定对象强转为ServletRequestDataBinder
ServletRequestDataBinder.bind(servletRequest)开始绑定
根据request对象创建一个MutablePropertyValuesfont color=\"#c41230\
ServletRequestParameterPropertyValues.ServletRequestParameterPropertyValues构造方法
他会先调用WebUtils.getParametersStartingWith来获取一个Map对象获取参数对应的值
Enumeration<String> paramNames = request.getParameterNames()获取参数枚举
创建一个treeMap用来保存参数
paramNames.nextElement() 获取参数名gameId
request.getParameterValues(paramName) 根据参数名获取参数值
将此参数放入到map中此时map中包含数据
MutablePropertyValues.MutablePropertyValues(Map original)根据返回的map调用此类的构造方法
将map放入到名为propertyValueList的集合中
ServletRequestDataBinder.doBind(mpvs)在实现绑定前要执行字段默认值和标记检查
checkFieldMarkers检查以字段标记前缀开头的字段。如果字段标记存在表明字段存在于表单中。如果属性值不包含相应的字段值,则该字段将被视为空,并将被适当重置。
调用DataBinder.doBind
checkAllowedFields删除不允许的字段值
PropertyAccessorUtils.canonicalPropertyName移除字段旁边的单引号或双引号{@code map['key']} -> {@code map[key]}{@code map[\"key\"]} -> {@code map[key]}
checkRequiredFields根据所需字段检查给定的属性值,在适当的地方生成缺失的字段错误。
applyPropertyValues将给定的属性值应用于目标对象。默认实现将所有提供的属性值应用为bean属性值。
AbstractPropertyAccessor.setPropertyValues
获取参数名称gameId
getPropertyNameTokens将属性名解析为一个属性名标记PropertyTokenHolder
给PropertyValue的resolvedTokens属性赋值
PropertyDescriptor pd = PropertyValue.resolvedDescriptor;
PropertyDescriptor类:(属性描述器)JDK java.beans包下的一个类
从pd中获取该参数的readMethod
执行readMethod.invoke(Game)获取旧值
convertForProperty这里获得了根据类型转换后的参数的值 1
new 了一个property类
BeanWrapperImpl.convertIfNecessary
convertIfNecessary
TypeConverterDelegate.convertIfNecessary将指定属性的值转换为所需类型
将请求参数和方法形参绑定到实例中
validateIfApplicable检查方法是否有Validated注解
将Modelset到mavContainer中
ReflectionUtils.makeAccessible(getBridgedMethod());将方法设置为可执行method.setAccessible(true);
setResponseStatus如果有responseStatus注解则设置返回响应值
this.returnValueHandlers.handleReturnValue
RequestResponseBodyMethodProcessor.handleReturnValue
writeWithMessageConverters将给定的返回值写入给定的web请求
getModelAndView
applyDefaultViewName
mappedHandler.applyPostHandle
processDispatchResult
triggerAfterCompletion
resetContextHolders
requestAttributes.requestCompleted()
executeRequestDestructionCallback单独启动一个线程执行请求完成后已注册执行的所有回调。
updateAccessedSessionAttributes
publishRequestHandledEvent
OncePerRequestFilter.doFilter
0 条评论
回复 删除
下一页