/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.mvc.method.annotation;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.*;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.*;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.*;
import org.springframework.web.method.support.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
import org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
* 支持的 {@link AbstractHandlerMethodAdapter} 扩展
* {@link RequestMapping @RequestMapping} 注释为 {@link HandlerMethod HandlerMethods}。
*
* <p>可以通过添加对自定义参数和返回值类型的支持
* {@link #setCustomArgumentResolvers} 和 {@link #setCustomReturnValueHandlers},
* 或者,重新配置所有参数和返回值类型,
* 使用 {@link #setArgumentResolvers} 和 {@link #setReturnValueHandlers}。
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @see HandlerMethodArgumentResolver
* @see HandlerMethodReturnValueHandler
* @since 3.1
*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
/**
* MethodFilter 匹配 {@link InitBinder @InitBinder} 方法。
*/
public static final MethodFilter INIT_BINDER_METHODS = method ->
AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
/**
* MethodFilter 匹配 {@link ModelAttribute @ModelAttribute} 方法。
*/
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
(!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) &&
AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
@Nullable
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@Nullable
private List<ModelAndViewResolver> modelAndViewResolvers;
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
private List<HttpMessageConverter<?>> messageConverters;
private List<Object> requestResponseBodyAdvice = new ArrayList<>();
@Nullable
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
@Nullable
private Long asyncRequestTimeout;
private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
private boolean ignoreDefaultModelOnRedirect = false;
private int cacheSecondsForSessionAttributeHandlers = 0;
private boolean synchronizeOnSession = false;
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
@Nullable
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64);
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<>(64);
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();
public RequestMappingHandlerAdapter() {
this.messageConverters = new ArrayList<>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
} catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
/**
* 为自定义参数类型提供解析器。自定义解析器已订购
* 在内置的之后。覆盖对参数的内置支持
* 解析使用 {@link #setArgumentResolvers} 代替。
*/
public void setCustomArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
this.customArgumentResolvers = argumentResolvers;
}
/**
* 返回自定义参数解析器,或 {@code null}。
*/
@Nullable
public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
return this.customArgumentResolvers;
}
/**
* 配置支持的参数类型的完整列表,从而覆盖
* 否则默认配置的解析器。
*/
public void setArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
if (argumentResolvers == null) {
this.argumentResolvers = null;
} else {
this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
this.argumentResolvers.addResolvers(argumentResolvers);
}
}
/**
* 返回配置的参数解析器,或者可能 {@code null} 如果
* 尚未通过 {@link #afterPropertiesSet()} 初始化。
*/
@Nullable
public List<HandlerMethodArgumentResolver> getArgumentResolvers() {
return (this.argumentResolvers != null ? this.argumentResolvers.getResolvers() : null);
}
/**
* 在 {@code @InitBinder} 方法中配置支持的参数类型。
*/
public void setInitBinderArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
if (argumentResolvers == null) {
this.initBinderArgumentResolvers = null;
} else {
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
this.initBinderArgumentResolvers.addResolvers(argumentResolvers);
}
}
/**
* 返回 {@code @InitBinder} 方法的参数解析器,或者可能
* {@code null} 如果尚未通过 {@link #afterPropertiesSet()} 初始化。
*/
@Nullable
public List<HandlerMethodArgumentResolver> getInitBinderArgumentResolvers() {
return (this.initBinderArgumentResolvers != null ? this.initBinderArgumentResolvers.getResolvers() : null);
}
/**
* 为自定义返回值类型提供处理程序。自定义处理程序是
* 在内置的之后排序。覆盖对内置的支持
* 返回值处理使用 {@link #setReturnValueHandlers}。
*/
public void setCustomReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
this.customReturnValueHandlers = returnValueHandlers;
}
/**
* 返回自定义返回值处理程序,或 {@code null}.
*/
@Nullable
public List<HandlerMethodReturnValueHandler> getCustomReturnValueHandlers() {
return this.customReturnValueHandlers;
}
/**
* C配置支持的返回值类型的完整列表,从而*覆盖默认情况下会配置的处理程序。
*/
public void setReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
if (returnValueHandlers == null) {
this.returnValueHandlers = null;
} else {
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
this.returnValueHandlers.addHandlers(returnValueHandlers);
}
}
/**
* 返回配置的处理程序,如果没有,则可能返回 {@code null}
* 尚未通过 {@link #afterPropertiesSet()} 初始化。
*/
@Nullable
public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
return (this.returnValueHandlers != null ? this.returnValueHandlers.getHandlers() : null);
}
/**
* 提供自定义 {@link ModelAndViewResolver ModelAndViewResolvers}。
* <p><strong>注意:</strong>此方法可用于向后
* 仅兼容性。但是,建议重新编写一个
* {@code ModelAndViewResolver} 作为 {@link HandlerMethodReturnValueHandler}。
* 两个接口之间的适配器是不可能的,因为
* {@link HandlerMethodReturnValueHandler#supportsReturnType} 方法
* 无法实现。因此 {@code ModelAndViewResolver} 是有限的
* 在所有其他返回值之后总是在最后被调用
* 处理程序有机会。
* <p>{@code HandlerMethodReturnValueHandler} 提供更好的访问
* 返回类型和控制器方法信息并可以订购
* 相对于其他返回值处理程序自由。
*/
public void setModelAndViewResolvers(@Nullable List<ModelAndViewResolver> modelAndViewResolvers) {
this.modelAndViewResolvers = modelAndViewResolvers;
}
/**
* 返回配置好的{@link ModelAndViewResolver ModelAndViewResolvers},或者{@code null}。
*/
@Nullable
public List<ModelAndViewResolver> getModelAndViewResolvers() {
return this.modelAndViewResolvers;
}
/**
* 设置 {@link ContentNegotiationManager} 以用于确定请求的媒体类型。
* 如果未设置,则使用默认构造函数。
*/
public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) {
this.contentNegotiationManager = contentNegotiationManager;
}
/**
* 提供用于参数解析器和返回值的转换器
* 支持读取和/或写入主体的处理程序
* 请求和响应。
*/
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
/**
* 返回配置的消息正文转换器。
*/
public List<HttpMessageConverter<?>> getMessageConverters() {
return this.messageConverters;
}
/**
* 添加一个或多个 {@code RequestBodyAdvice} 实例来拦截
* 在它被读取和转换为 {@code @RequestBody} 之前请求和
* {@code HttpEntity} 方法参数。
*/
public void setRequestBodyAdvice(@Nullable List<RequestBodyAdvice> requestBodyAdvice) {
if (requestBodyAdvice != null) {
this.requestResponseBodyAdvice.addAll(requestBodyAdvice);
}
}
/**
* 添加一个或多个 {@code ResponseBodyAdvice} 实例来拦截
* {@code @ResponseBody} 或 {@code ResponseEntity} 返回之前的响应
* 值被写入响应正文。
*/
public void setResponseBodyAdvice(@Nullable List<ResponseBodyAdvice<?>> responseBodyAdvice) {
if (responseBodyAdvice != null) {
this.requestResponseBodyAdvice.addAll(responseBodyAdvice);
}
}
/**
* 提供具有“全局”初始化的 WebBindingInitializer 以应用
* 到每个 DataBinder 实例。
*/
public void setWebBindingInitializer(@Nullable WebBindingInitializer webBindingInitializer) {
this.webBindingInitializer = webBindingInitializer;
}
/**
* 返回配置的 WebBindingInitializer,如果没有,则返回 {@code null}。
*/
@Nullable
public WebBindingInitializer getWebBindingInitializer() {
return this.webBindingInitializer;
}
/**
* 设置默认 {@link AsyncTaskExecutor} 以在控制器方法
* 返回一个 {@link Callable}。控制器方法可以覆盖此默认值
* 通过返回 {@link WebAsyncTask} 以每个请求为基础。
* <p>默认使用 {@link SimpleAsyncTaskExecutor} 实例。
* 建议将生产中的默认设置更改为简单的执行程序
* 不重复使用线程。
*/
public void setTaskExecutor(AsyncTaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* 指定并发处理之前的时间量(以毫秒为单位)
* 应该超时。在 Servlet 3 中,超时从主请求之后开始
* 处理线程已退出并在请求再次分派时结束
* 用于进一步处理同时产生的结果。
* <p>如果没有设置这个值,底层的默认超时时间
* 使用实现,例如使用 Servlet 3 在 Tomcat 上运行 10 秒。
*
* @param timeout the timeout value in milliseconds
*/
public void setAsyncRequestTimeout(long timeout) {
this.asyncRequestTimeout = timeout;
}
/**
* 配置 {@code CallableProcessingInterceptor} 以注册异步请求.
*
* @param interceptors the interceptors to register
*/
public void setCallableInterceptors(List<CallableProcessingInterceptor> interceptors) {
this.callableInterceptors = interceptors.toArray(new CallableProcessingInterceptor[0]);
}
/**
* 配置 {@code DeferredResultProcessingInterceptor} 以注册异步请求。
*
* @param interceptors the interceptors to register
*/
public void setDeferredResultInterceptors(List<DeferredResultProcessingInterceptor> interceptors) {
this.deferredResultInterceptors = interceptors.toArray(new DeferredResultProcessingInterceptor[0]);
}
/**
* 为要支持的反应库类型配置注册表
* 从控制器方法返回值。
*
* @since 5.0.5
*/
public void setReactiveAdapterRegistry(ReactiveAdapterRegistry reactiveAdapterRegistry) {
this.reactiveAdapterRegistry = reactiveAdapterRegistry;
}
/**
* 返回已配置的适配器反应类型注册表。
*
* @since 5.0
*/
public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
return this.reactiveAdapterRegistry;
}
/**
* 默认情况下,“默认”模型的内容在
* 渲染和重定向场景。或者控制器方法
* 可以声明一个 {@link RedirectAttributes} 参数并使用它来提供
* 重定向的属性。
* <p>将此标志设置为 {@code true} 保证“默认”模型为
* 从未在重定向场景中使用,即使 RedirectAttributes 参数
* 未声明。将其设置为 {@code false} 表示“默认”模型
* 如果控制器方法没有声明
* RedirectAttributes 参数。
* <p>默认设置是 {@code false} 但新的应用程序应该
* 考虑将其设置为 {@code true}。
*
* @see RedirectAttributes
*/
public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {
this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
}
/**
* 指定用于存储会话属性的策略。默认是
* {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
* 在具有相同属性的 HttpSession 中存储会话属性
* 模型中的名称。
*/
public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
this.sessionAttributeStore = sessionAttributeStore;
}
/**
* 缓存由 {@code @SessionAttributes} 注释处理程序生成的内容
* 对于给定的秒数。
* <p>可能的值是:
* <ul>
* <li>-1:不生成缓存相关的头</li>
* <li>0 (默认值): "Cache-Control: no-store" 将阻止缓存</li>
* <li>1 或更高:"Cache-Control: max-age=seconds" 会要求缓存内容;
* 处理会话属性时不建议</li>
* </ul>
* <p>与“cacheSeconds”属性相反,它适用于所有一般
* 处理程序(但不是 {@code @SessionAttributes} 注释处理程序),
* 此设置仅适用于 {@code @SessionAttributes} 处理程序。
*
* @see #setCacheSeconds
* @see org.springframework.web.bind.annotation.SessionAttributes
*/
public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) {
this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers;
}
/**
* 设置控制器执行是否应该在会话上同步,
* 序列化来自同一客户端的并行调用。
* <p>更具体地说,{@code handleRequestInternal} 的执行
* 如果此标志为“true”,方法将同步。最好的
* 会话互斥将用于同步;理想情况下,这将
* 是 HttpSessionMutexListener 公开的互斥锁。
* <p>会话互斥量保证是同一个对象
* 会话的整个生命周期,在定义的键下可用
* 通过 {@code SESSION_MUTEX_ATTRIBUTE} 常量。它作为一个
* 安全参考同步锁定当前会话。
* <p>在很多情况下,HttpSession 引用本身就是一个安全的互斥锁
* 也是如此,因为它始终是相同的对象引用
* 相同的活动逻辑会话。但是,这并不能保证
* 不同的servlet容器;唯一 100% 安全的方法是会话互斥锁。
*
* @see org.springframework.web.util.HttpSessionMutexListener
* @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
*/
public void setSynchronizeOnSession(boolean synchronizeOnSession) {
this.synchronizeOnSession = synchronizeOnSession;
}
/**
* 设置 ParameterNameDiscoverer 以在需要时用于解析方法参数名称
* (例如对于默认属性名称)。
* <p>Default is a {@link org.springframework.core.DefaultParameterNameDiscoverer}.
*/
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
* 解析表达式需要一个 {@link ConfigurableBeanFactory}
* 在方法参数默认值中。
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (beanFactory instanceof ConfigurableBeanFactory) {
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
}
/**
* 返回此 bean 实例的拥有工厂,如果没有,则返回 {@code null}。
*/
@Nullable
protected ConfigurableBeanFactory getBeanFactory() {
return this.beanFactory;
}
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
//加载加了ControllerAdvice注解的类
initControllerAdviceCache();
//
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
//处理加了ControllerAdvice注解的类
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
}
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
}
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
if (logger.isDebugEnabled()) {
int modelSize = this.modelAttributeAdviceCache.size();
int binderSize = this.initBinderAdviceCache.size();
int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
logger.debug("ControllerAdvice beans: none");
} else {
logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
}
}
}
// Count all advice, including explicit registrations..
private int getBodyAdviceCount(Class<?> adviceType) {
List<Object> advice = this.requestResponseBodyAdvice;
return RequestBodyAdvice.class.isAssignableFrom(adviceType) ?
RequestResponseBodyAdviceChain.getAdviceByType(advice, RequestBodyAdvice.class).size() :
RequestResponseBodyAdviceChain.getAdviceByType(advice, ResponseBodyAdvice.class).size();
}
/**
* 返回要使用的参数解析器列表,包括内置解析器
* 和通过 {@link #setCustomArgumentResolvers} 提供的自定义解析器。
*/
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
/**
* 返回用于 {@code @InitBinder} 的参数解析器列表
* 包括内置和自定义解析器的方法。
*/
private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
return resolvers;
}
/**
* 返回要使用的返回值处理程序列表,包括内置和
* 通过 {@link #setReturnValueHandlers} 提供的自定义处理程序。
*/
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
} else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
/**
* 始终返回 {@code true},因为任何方法参数和返回值
* 类型会以某种方式进行处理。无法识别方法参数
* 被任何 HandlerMethodArgumentResolver 解释为请求参数
* 如果它是简单类型,否则作为模型属性。一个返回值
* 不被任何 HandlerMethodReturnValueHandler 识别的将被解释
* 作为模型属性。
*/
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
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)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
prepareResponse(response);
}
}
return mav;
}
/**
* 此实现始终返回 -1。 {@code @RequestMapping} 方法可以
* 计算lastModified值,调用{@link WebRequest#checkNotModified(long)},
* 如果调用的结果是 {@code true},则返回 {@code null}。
*/
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
/**
* 返回给定处理程序类型的 {@link SessionAttributesHandler} 实例
* (从不{@code null})。
*/
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, this.sessionAttributeStore);
this.sessionAttributesHandlerCache.put(handlerType, sessionAttrHandler);
}
}
}
return sessionAttrHandler;
}
/**
* 调用 {@link RequestMapping} 处理程序方法准备 {@link ModelAndView}
* 如果需要视图分辨率。
*
* @see #createInvocableHandlerMethod(HandlerMethod)
* @since 4.2
*/
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = 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);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}
/**
* 从给定的 {@link HandlerMethod} 定义创建一个 {@link ServletInvocableHandlerMethod}。
*
* @param handlerMethod the {@link HandlerMethod} definition
* @return the corresponding {@link ServletInvocableHandlerMethod} (or custom subclass thereof)
* @since 4.2
*/
protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
return new ServletInvocableHandlerMethod(handlerMethod);
}
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
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<>();
// Global methods first
this.modelAttributeAdviceCache.forEach((clazz, methodSet) -> {
if (clazz.isApplicableToBeanType(handlerType)) {
Object bean = clazz.resolveBean();
for (Method method : methodSet) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
});
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
if (this.argumentResolvers != null) {
attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
attrMethod.setDataBinderFactory(factory);
return attrMethod;
}
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
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);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
// Global methods first
this.initBinderAdviceCache.forEach((clazz, methodSet) -> {
if (clazz.isApplicableToBeanType(handlerType)) {
Object bean = clazz.resolveBean();
for (Method method : methodSet) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
});
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
return createDataBinderFactory(initBinderMethods);
}
private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
if (this.initBinderArgumentResolvers != null) {
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
}
binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return binderMethod;
}
/**
* 创建新的 InitBinderDataBinderFactory 实例的模板方法。
* <p>默认实现创建了一个 ServletRequestDataBinderFactory。
* 这可以被自定义 ServletRequestDataBinder 子类覆盖。
*
* @param binderMethods {@code @InitBinder} methods
* @return the InitBinderDataBinderFactory instance to use
* @throws Exception in case of invalid state or arguments
*/
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
throws Exception {
return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
}
|