springMVC分析-3
springMVC的handlerAdapter处理
参数转换,数据绑定,参数验证
springMVC 3.1以后,其注册的是RequestMappingHandlerAdapter,来看看这个类
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
private static final boolean completionStagePresent = ClassUtils.isPresent("java.util.concurrent.CompletionStage",
RequestMappingHandlerAdapter.class.getClassLoader());
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private HandlerMethodArgumentResolverComposite argumentResolvers;
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
private List<ModelAndViewResolver> modelAndViewResolvers;
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
private List<HttpMessageConverter<?>> messageConverters;
private List<Object> requestResponseBodyAdvice = new ArrayList<Object>();
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
private Long asyncRequestTimeout;
private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
private boolean ignoreDefaultModelOnRedirect = false;
private int cacheSecondsForSessionAttributeHandlers = 0;
private boolean synchronizeOnSession = false;
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache =
new ConcurrentHashMap<Class<?>, SessionAttributesHandler>(64);
private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<Class<?>, Set<Method>>(64);
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache =
new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<Class<?>, Set<Method>>(64);
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache =
new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
}
这个类是个适配器模式,其包含了大量的解析器。而这个类实现了InitializingBean,在其被spring实例化时,会调用afterPropertiesSet()方法进行初始化,还有其在
<mvc:annotation-driven > 解析出的节点,所有可以看出来afterPropertiesSet()是注册默认的解析器。
//构造函数
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
this.messageConverters.add(new SourceHttpMessageConverter<Source>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
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);
}
}
看initConstrllerAdviceCache()这个方法,
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
//从beanFactory找出所有的ControllerAdvice注解的bean,并将ControllerAdvice注解中的参数解析出来,并封装到ControllerAdviceBean
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
//排序
AnnotationAwareOrderComparator.sort(beans);
List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
for (ControllerAdviceBean bean : beans) {
// @ModelAttribute 注解的方法
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(bean, attrMethods);
logger.info("Detected @ModelAttribute methods in " + bean);
}
//@InitBinder 注解的方法
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(bean, binderMethods);
logger.info("Detected @InitBinder methods in " + bean);
}
//判断RequestBodyAdvice 是否是bean的父类
if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
requestResponseBodyAdviceBeans.add(bean);
logger.info("Detected RequestBodyAdvice bean in " + bean);
}
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
requestResponseBodyAdviceBeans.add(bean);
logger.info("Detected ResponseBodyAdvice bean in " + bean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
初始化这些adviceBean做什么的呢?我们继续玩下看,看RequestMappingHandlerAdapter的处理方法,在DispacherServlet里面的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
然后调用RequestMappingHandlerAdapter的父类AbstractHandlerMethodAdapter的handler方法进行处理,而这个handler方法,直接转给了handleInternal()这个方法,这个方法是个抽象方法,故其具体实现在其子类,我们看RequestMappingHandlerAdapter的具体实现
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//检查是否支持该请求方法,如get,post这类的,以及requirdSession
checkRequest(request);
//检查是否包含@SessionAttributes 这个注解在handlerMethod的bean中,如有则配置header中的Cache-Control,默认是no-store
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
//设置Cache-Control
prepareResponse(response);
}
// Execute invokeHandlerMethod in synchronized block if required.
//请求是否需要根据session来加锁,默认是false
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandlerMethod(request, response, handlerMethod);
}
}
}
//处理方法
return invokeHandlerMethod(request, response, handlerMethod);
}
再往后面的处理方法看
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//创建出ServletInvocableHandlerMethod 并初始化出@ResponseStatus里面的值
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//设置处理参数的聚合类,Composite
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
//设置处理返回值的聚合类
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();
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);
}
从这个方法中,我们需要看的是请求参数是如何绑定到方法参数上的
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
从上面可以看出来其生成了一个WebDataBinderFactory 的参数绑定工厂,来看看这个工厂是怎么生成的
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType();
//从初始化的缓存中取
Set<Method> methods = this.initBinderCache.get(handlerType);
if (methods == null) {
//找出在该controller中的@InitBinder的方法,并加入缓存中,这个缓存是个ConcurrentHashMap
methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
//从全局的@InitBinder中取,在@ConstrollerAdvice中配置的@InitBinder方法
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));
}
}
}
//将上面两种聚合
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
// 并和RequestMappingHandlerAdapter的ConfigurableWebBindingInitializer
return createDataBinderFactory(initBinderMethods);
}
//ConfigurableWebBindingInitializer包含的属性
public class ConfigurableWebBindingInitializer implements WebBindingInitializer {
private boolean autoGrowNestedPaths = true;
private boolean directFieldAccess = false;
private MessageCodesResolver messageCodesResolver;
private BindingErrorProcessor bindingErrorProcessor;
private Validator validator;
private ConversionService conversionService;
private PropertyEditorRegistrar[] propertyEditorRegistrars;
}
可以看出这个WebDataBinderFactory 包含了自定义的数据绑定方法还有springMVC默认注册的,以及Validator.
有了WebDataBinderFactory,继续分析其是如何使用的。
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//得到controller的返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//交给returnValueHandlers进行处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
来看看是如何获取到controller的返回值,中间做了哪些处理
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取到该方法的入参
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
//使用反射调用该controller的具体处理方法
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
我们可以看到整个流程下来,数据绑定的处理就在InvocableHandlerMethod中的getMethodArgumentValues()方法中
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
throw new IllegalStateException(msg);
}
}
return args;
}
可以看到,其最后交给了 HandlerMethodArgumentResolverComposite 这个 HandlerMethodArgumentResolver的聚合类处理
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//根据参数获取到具体的解析类
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
//解析类解析
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
可以看出这又有一个扩展点 HandlerMethodArgumentResolver,我们可以实现这个接口,自定义出解析类。
在HandlerMethodArgumentResolver 实现了对参数类型的转换,格式转换,以及验证的操作。默认注册的HandlerMethodArgumentResolver 有哪些呢
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver
org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
继续在看获得controller的返回值后,然后交给了HandlerMethodReturnValueHandlerComposite 对返回值进行处理,比如像注解为@ResponseBody的,则交给RequestResponseBodyMethodProcessor进行处理,可以看出这又是个一个扩展点,其可以用来对controller的返回值进行再处理。其默认注册的HandlerMethodReturnValueHandler有以下,按以下顺序进行匹配,最先匹配原则
//处理返回ModelAndView的
org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler
org.springframework.web.method.annotation.ModelMethodProcessor
//处理返回的参数是View的子类的
org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler
//请求返回HttpEntity的
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor
org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.ListenableFutureReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.CompletionStageReturnValueHandler
//处理方法上包含@ModelAttribute的
org.springframework.web.method.annotation.ModelAttributeMethodProcessor
//处理包含这个@ResponseBody
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
//处理返回string类型的视图,已经重定向,转发
org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler
//处理返回值是Map的子类
org.springframework.web.method.annotation.MapMethodProcessor