RequestMappingHanderAdapter的请求处理
RequestMappingHanderAdapter处理请求的入口方法是handleInternal:
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 最终返回类型
ModelAndView mav;
// 检查请求类型和session支持
checkRequest(request);
// 执行请求的处理
if (this.synchronizeOnSession) {//是否对Session同步
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 给缓存设置过期时间
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
// 检查处理器是否有@SessionAttributes注解
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
我们可以看到处理请求的最终会返回一个ModelAndView的对象
checkRequest方法
checkRequest方法源码:
protected final void checkRequest(HttpServletRequest request) throws ServletException {
// 根据supportedMethods属性判断是否支持当前请求的请求类型
String method = request.getMethod();
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(
method, StringUtils.toStringArray(this.supportedMethods));
}
// 当requireSession(默认false)为true时,检查Session是否存在
if (this.requireSession && request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
根据supportedMethods属性判断是否支持当前请求的请求类型
那么supportedMethods属性是如何初始化的?
private Set<String> supportedMethods;
supportedMethods属性默认为空,可以在RequestMappingHandlerAdapter初始化时进行设置
public WebContentGenerator(boolean restrictDefaultSupportedMethods) {
if (restrictDefaultSupportedMethods) {
this.supportedMethods = new LinkedHashSet<String>(4);
this.supportedMethods.add(METHOD_GET);
this.supportedMethods.add(METHOD_HEAD);
this.supportedMethods.add(METHOD_POST);
}
initAllowHeader();
}
如果在构造方法中为restrictDefaultSupportedMethods传true
supportedMethods只会支持GET,HEAD,POST三种请求
public AbstractHandlerMethodAdapter() {
super(false);
}
AbstractHandlerMethodAdapter继承自WebContentGenerator
RequestMappingHandlerAdapter的父类AbstractHandlerMothodAdapter中
直接传入了false,默认不检查请求类型
getSessionAttributesHandler
getSessionAttributesHandler方法源码:
private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod handlerMethod) {
Class<?> handlerType = handlerMethod.getBeanType();
SessionAttributesHandler sessionAttrHandler = this.sessionAttributesHandlerCache.get(handlerType);
if (sessionAttrHandler == null) {
synchronized (this.sessionAttributesHandlerCache) {
sessionAttrHandler = this.sessionAttributesHandlerCache.get(handlerType);
if (sessionAttrHandler == null) {
sessionAttrHandler = new SessionAttributesHandler(handlerType, sessionAttributeStore);
this.sessionAttributesHandlerCache.put(handlerType, sessionAttrHandler);
}
}
}
return sessionAttrHandler;
}
// 是否存在attributeNames或attributeTypes
public boolean hasSessionAttributes() {
return (this.attributeNames.size() > 0 || this.attributeTypes.size() > 0);
}
sessionAttributesHandlerCache属性是一个new好的空集合
private final Map<Class<?>, SessionAttributesHandler>
sessionAttributesHandlerCache = new ConcurrentHashMap<Class<?>, SessionAttributesHandler>(64);
首先根据handlerType到SessionAttributesHandler中查找SessionAttributesHandler
如果没有就创建出来添加进去,这里使用了一个双重校验锁并且使用了一种懒汉式的加载方式
这其中用又到了一个sessionAttributeStore属性
sessionAttributeStore属性
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
DefaultSessionAttributeStore实现了SessionAttributeStore接口
public class DefaultSessionAttributeStore implements SessionAttributeStore {
private String attributeNamePrefix = "";
public DefaultSessionAttributeStore() {
}
public void setAttributeNamePrefix(String attributeNamePrefix) {
this.attributeNamePrefix = attributeNamePrefix != null?attributeNamePrefix:"";
}
public void storeAttribute(WebRequest request, String attributeName, Object attributeValue) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
Assert.notNull(attributeValue, "Attribute value must not be null");
String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
request.setAttribute(storeAttributeName, attributeValue, 1);
}
public Object retrieveAttribute(WebRequest request, String attributeName) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
return request.getAttribute(storeAttributeName, 1);
}
public void cleanupAttribute(WebRequest request, String attributeName) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
request.removeAttribute(storeAttributeName, 1);
}
protected String getAttributeNameInSession(WebRequest request, String attributeName) {
return this.attributeNamePrefix + attributeName;
}
}
从代码可以看到SessionAttributeStore属性并不是用来保存SessionAttribute参数的容器,
而是保存SessionAttribute的工具,SessionAttribute最终被保存在request中
设置缓存的过期时间
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
// 如果包含SessionAttributes注解,且有name或type属性
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// 设置缓存时间,cacheSecondsForSessionAttributeHandlers默认0
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
// cacheSeconds>0设置缓存时间,cacheSeconds=0阻止缓存
protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds) {
if (this.useExpiresHeader || !this.useCacheControlHeader) {
// Deprecated HTTP 1.0 cache behavior, as in previous Spring versions
if (cacheSeconds > 0) {
cacheForSeconds(response, cacheSeconds);
}
else if (cacheSeconds == 0) {
preventCaching(response);
}
}
else {
CacheControl cControl;
if (cacheSeconds > 0) {
cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);
if (this.alwaysMustRevalidate) {
cControl = cControl.mustRevalidate();
}
}
else if (cacheSeconds == 0) {
cControl = (this.useCacheControlNoStore ? CacheControl.noStore() : CacheControl.noCache());
}
else {
cControl = CacheControl.empty();
}
applyCacheControl(response, cControl);
}
}
invokeHandlerMethod
invokeHandlerMethod是一个核心方法,他具体执行请求的处理
invokeHandlerMethod源码:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 使用request和response创建ServletWebRequest类型的webRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 初始化三个变量
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 创建ModelAndViewContainer,用于保存Model和View
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);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 处理请求
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
首先使用request和response创建ServletWebRequest类型的webRequest
ArgumentResolve解析参数是用的request就是这个webRequest
然后,初始化三个变量WebDataBinderFactory,ModelFactory,ServletInvocableHandlerMethod
之后新建传递参数的,ModelAndViewContainer容器,执行请求,请求执行完成的后置处理
WebDataBinderFactory初始化
WebDataBinderFactory:
用于创建WebDataBinder
WebDataBinder:
用于参数绑定,实现参数和String之间的类型转换
ArgumentResolve进行参数解析的过程中会用到WebDataBinder
ModelFactory在更新Model是也会用到WebDataBinder
getDataBinderFactory源码:
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
// 检查当前Handler中的InitBinder方法是否已经在缓存中
Class<?> handlerType = handlerMethod.getBeanType();
Set<Method> methods = this.initBinderCache.get(handlerType);
// 如果没在缓存中,找到并设置到缓存
if (methods == null) {
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
// 保存initBinder方法的集合
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
// 将所有符合条件的全局InitBinder方法添加到initBinderMethods
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
}
// 将当前Handler中的InitBinder方法添加到initBinderMethods
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
// 创建DataBinderFactory并返回,DataBinderFactory和InitBinder方法相关联
return createDataBinderFactory(initBinderMethods);
}
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
throws Exception {
return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}
WebDataBinderFactory的创建过程:
找出符合条件的@InitBinder方法,
使用它们创建ServletRequestDataBinderFactory类型的WebDataBinderFactory
InitBinder方法包含两部分:
1,注释了@ControllerAdvice并且符合要求的全局处理器中的InitBinder方法
(创建RequestMappingHandlerAdapter时已经设置到缓存)
2,处理自身的InitBinder方法(第一次调用后保存到缓存中)
添加顺序是先全局后自身
ModelFactory初始化
ModelFactory:
ModelFactory是用来处理Model的,有两个作用:
1,处理器处理前对Model进行初始化
2,处理完请求后对Model参数进行更新
Model初始化包含3部分:
1,将原来的SessionAttributes中的值设置到Model中
2,执行注视了@ModelAttribute的方法并将其值设置到model
3,处理器中注释了@ModelAttribute的参数如果同时也在SessionAttributes中配置了
而且在mavContainer中没有值,则从全部SessionAttributes中查找出并设置进去
(可能是其他处理器设置的值)
Model更新:
先对SessionAttributes进行设置
如果处理器调用了SessionStatus#setComplete,则清空SessionAttributes
否则将mavContainer中的defaultModel中响应参数设置到SessionAttributes
然后按需要给Model设置参数对应的BindingResult
getModelFactory源码:
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
// 获取SessionAttributesHandler
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
// 获取有@ModelAttribute没有@RequestMapping的方法,使用后添加到缓存
Class<?> handlerType = handlerMethod.getBeanType();
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
// 先添加全局@ControllerAdvice方法,后添加当前处理器定义的@ModelAttribute方法
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
}
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
// 创建ModelFactory
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);使用了3个参数
1,注释了@ModelAttribute的方法
1)@ControllerAdvice类中定义的全局@ModelAttribute方法
2)处理器自己的@ModelAttribute方法
先添加全局,后添加自己的
2,WebDataBinderFactory,前面创建出来的
3,SessionAttributesHandler,由getSessionAttributesHandler获得
ServletInvocableHandlerMethod初始化
ServletInvocableHandlerMethod继承自HandlerMethod,并且可以直接执行
此方法就是情急请求的处理方法,参数绑定,请求处理,返回值处理都是在此方法中完成的
部分源码:
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
return new ServletInvocableHandlerMethod(handlerMethod);
}
首先使用handlerMethod新建了一个ServletInvocableHandlerMethod类
然后设置argumentResolvers,returnValueHandlers,binderFactory,parameterNameDiscoverer
ModelAndViewContainer初始化
ModelAndViewContainer用于保存Model和View
部分源码:
// 创建ModelAndViewContainer用于保存Model和View
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 将FlashMap中的数据设置到Model
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 使用modelFactory将SessionAttributes和注释了@ModelAttributede的方法的参数设置到Model
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 根据配置对ignoreDefaultModelOnRedirect进行设置
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
ModelAndViewContainer贯穿于整个处理过程,对mavContainer设置了3部分内容:
1,将FlashMap中的数据设置到Model
2,使用modelFactory将SessionAttributes和注释了@ModelAttributede的方法的参数设置到Model
3,根据配置对ignoreDefaultModelOnRedirect进行设置
public void initModel(NativeWebRequest request, ModelAndViewContainer container,
HandlerMethod handlerMethod) throws Exception {
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
container.mergeAttributes(sessionAttributes);
invokeModelAttributeMethods(request, container);
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!container.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
}
container.addAttribute(name, value);
}
}
}
invokeAndHandler执行请求
invocableMethod.invokeAndHandle(webRequest, mavContainer);
直接调用了ServletInvocableHandlerMethod#invokeAndHandle方法执行请求,后续这部分会详细分析
getModelAndView请求处理完成后的后置处理
相关源码:
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
// 调用updateModel更新Model(设置了SessionAttributes和给Model设置BindingResult)
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
// 根据mavContainer创建ModelAndView
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
// 如果model是RedirectAttributes类型,将值设置到FlashMap
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
一共做了3件事:
调用updateModel更新Model(设置了SessionAttributes和给Model设置BindingResult)
根据mavContainer创建ModelAndView
如果model是RedirectAttributes类型,将值设置到FlashMap
这里的model只有在处理器返回redirect类型的视图是才能是RedirectAttributes类型
在不返回redirect类型视图的处理器中,
即使使用RedirectAttributes设置了变量也不会保存到FlashMap
这部分会在ModelAndViewContainer时详细分析...
到这里整个RequestMappingHandlerAdapter处理请求的过程就分析完了
还有很多内部组件我们并没有分析到,接下来我们就一一进行分析