handlerAdapter与方法调用(参数的解析)
前提:当找到handler以后,那么就要让handler发挥作用,这个时候handlerAdapter就派上用场了 这里面比较复杂就是requestMappingHandlerAdapter了,其他的由于handler比较固定,基本上之前调用他们实现的接口的方法。 @Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
supportsInternal方法子类实现,用于扩展,但在requestMappingHandlerAdapter子类中并没有做什么,直接返回true。 @Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { return handleInternal(request, response, (HandlerMethod) handler);
} handleInternal方法也有子类实现。在调用handler之前,会做一些数据绑定,比如会查找@ControllerAdvice注解,查找@InitBinder,@ModuleAttribute,查找实现了RequestBodyAdvice的类等等。
初始化一些参数解析器,校验器 RequestMappingHandlerAdapter实现了InitializingBean接口,所以在初始化这个adapter并且设置了相应的属性之后就会调用afterPropertiesSet方法
@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;
}
if (logger.isInfoEnabled()) {
logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
}
//在applicationContext容器中找到被@controllerAdvice标注的bean,并排序
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
AnnotationAwareOrderComparator.sort(beans);
//创建实现了@responseBodyAdvice的bean
List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>(); for (ControllerAdviceBean bean : beans) {
//查找被@ModelAttribute注解标注的方法
Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(bean, attrMethods);
if (logger.isInfoEnabled()) {
logger.info("Detected @ModelAttribute methods in " + bean);
}
}
//查找被@InitBinder注解标注的方法
Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(bean, binderMethods);
if (logger.isInfoEnabled()) {
logger.info("Detected @InitBinder methods in " + bean);
}
}
//查找父类是RequestBodyAdvice的bean
if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
requestResponseBodyAdviceBeans.add(bean);
if (logger.isInfoEnabled()) {
logger.info("Detected RequestBodyAdvice bean in " + bean);
}
}
//查找父类是ResponseBodyAdvice的bean
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
requestResponseBodyAdviceBeans.add(bean);
if (logger.isInfoEnabled()) {
logger.info("Detected ResponseBodyAdvice bean in " + bean);
}
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
//将使用@ControllerAdvice注解找的bean放到最前面
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
} 方法返回后
接下来就开始初始化解析器了
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
} getDefaultArgumentResolvers方法
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); // 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())); // 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;
} 准备就绪之后,开始调用handleInternal方法 @Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav;
//检查是否支持当前请求的方法,检查session是否为必须的
checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required.
//执行session同步
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;
} protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response);
//创建data绑定工厂,数据绑定是用来与String进行参数转换的
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 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);
} private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType();
//从缓存中查找是否已经存在这个类型对应的@InitBinder方法
Set<Method> methods = this.initBinderCache.get(handlerType);
if (methods == null) {
//如果为空,就对当前handler进行遍历查找@InitBinder的方法
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
//保存到缓存中
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
// Global methods first遍历全局(也就是@ControllerAdvice标注的类的@InitBinder方法,这个在adapter的afterPropertiesSet方法中初始化的)
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
//创建InvocableHandlerMethod对象并添加
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
}
//添加完全局的之后,再添加当前处理器的
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
return createDataBinderFactory(initBinderMethods);
} public boolean isApplicableToBeanType(Class<?> beanType) {
//如果@controllerAdvice什么属性都没有写,说明将所有配置的方法应用到所有的handler中
if (!hasSelectors()) {
return true;
}
else if (beanType != null) {
for (String basePackage : this.basePackages) {
if (beanType.getName().startsWith(basePackage)) {
return true;
}
}
for (Class<?> clazz : this.assignableTypes) {
if (ClassUtils.isAssignable(clazz, beanType)) {
return true;
}
}
for (Class<? extends Annotation> annotationClass : this.annotations) {
if (AnnotationUtils.findAnnotation(beanType, annotationClass) != null) {
return true;
}
}
}
return false;
} private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
//InvocableHandlerMethod 是handlerMethod的子类
InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return binderMethod;
} 最后返回一个createDataBinderFactory(initBinderMethods); 回到invokeHandlerMethod方法,创建了DataBinderFactory后,接下来就是创建ModelFactory了 private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
//获取SessionAttributesHandler,这个处理器用来处理@SessionAttributes注解的方法
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
Class<?> handlerType = handlerMethod.getBeanType();
//获取标注了@ModelAttribute的方法
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
//如果缓存中没有就重新查找当前标注了@ModelAttribute的方法,并存到缓存中
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
// Global methods first添加全局的@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);
} //第一个参数传入的是标记了@ModelAttribute的方法,第二个参数数据绑定,第三个是@SessionAttributes注解对应的处理器
public ModelFactory(List<InvocableHandlerMethod> handlerMethods,
WebDataBinderFactory binderFactory, SessionAttributesHandler attributeHandler) { if (handlerMethods != null) {
for (InvocableHandlerMethod handlerMethod : handlerMethods) {
this.modelMethods.add(new ModelMethod(handlerMethod));
}
}
this.dataBinderFactory = binderFactory;
this.sessionAttributesHandler = attributeHandler;
} private ModelMethod(InvocableHandlerMethod handlerMethod) {
this.handlerMethod = handlerMethod;
for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
this.dependencies.add(getNameForParameter(parameter));
}
}
} 当缓存什么的都弄好了之后就开始处理当前handleMethod了
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//将FlashMap中的属性添加到mav容器中
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); public void initModel(NativeWebRequest request, ModelAndViewContainer container,
HandlerMethod handlerMethod) throws Exception {
//从sessionAttribute中回复参数到mavContainer中
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
//合并参数,因为sessionAttribute中的参数可能会与flashmap中的参数冲突,但不会覆盖原来的参数
container.mergeAttributes(sessionAttributes);
//调用modelAttribute注解的方法
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 + "'");
}
container.addAttribute(name, value);
}
}
} invokeModelAttributeMethods(request, container); private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
throws Exception { while (!this.modelMethods.isEmpty()) {
//获取第一个modelMethod方法,并将其移除,等下次调用的时候就就是第二个modelMethod,如果参数有@ModelAttribute,则优先处理
InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
//获取模型值,即属性key值
String modelName = modelMethod.getMethodAnnotation(ModelAttribute.class).value();
//如果已经存在了就不再调用
if (container.containsAttribute(modelName)) {
continue;
}
//调用方法
Object returnValue = modelMethod.invokeForRequest(request, container);
if (!modelMethod.isVoid()){
String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
if (!container.containsAttribute(returnValueName)) {
container.addAttribute(returnValueName, returnValue);
}
}
}
} private ModelMethod getNextModelMethod(ModelAndViewContainer container) {
//遍历所有的modelmethod,如果他们的依赖存在,就优先使用这个方法参数与中有@ModelAttribute注解的modelmethod方法,否则就直接返回第一个modelmethod
for (ModelMethod modelMethod : this.modelMethods) {
if (modelMethod.checkDependencies(container)) {
if (logger.isTraceEnabled()) {
logger.trace("Selected @ModelAttribute method " + modelMethod);
}
this.modelMethods.remove(modelMethod);
return modelMethod;
}
}
//获取第一个modelmethod,并将它已移除
ModelMethod modelMethod = this.modelMethods.get(0);
if (logger.isTraceEnabled()) {
logger.trace("Selected @ModelAttribute method (not present: " +
modelMethod.getUnresolvedDependencies(container)+ ") " + modelMethod);
}
this.modelMethods.remove(modelMethod);
return modelMethod;
} //
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());
}
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
} 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());
//尝试从给定的providedArgs参数查找对应类型的参数,如果找到就设置这个值到args数组中,这个providedArgs在这里是没有传递任何值的
args[i] = resolveProvidedArgument(parameter, providedArgs);
//如果不为空就continue,表示已经有值了
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;
} (this.argumentResolvers.supportsParameter(parameter)
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//先从缓存中找,如果没有找到,在遍历所有的解析器,这个解析器集合保存在一个解析器Composite类中,SpringMVC中这样的类一般是使用的责任链模式
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
} this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);方法体如下 @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的实现类有很多,这里选几个分析一下 首先先分析一下RequestResponseBodyMethodProcessor,这是一个集argumentResolve和handlerReturnValue于一身的类 直接看解析方法resolveArgument: @Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//使用转化器进行参数的转换
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter); WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); return arg;
} protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter methodParam,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); Object arg = readWithMessageConverters(inputMessage, methodParam, paramType);
if (arg == null) {
if (methodParam.getParameterAnnotation(RequestBody.class).required()) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
methodParam.getMethod().toGenericString());
}
}
return arg;
} readWithMessageConverters方法
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter param,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { MediaType contentType;
boolean noContentType = false;
try {
//获取请求的ContentType
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
//设置默认的contentType
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
//获取类的类型
Class<?> contextClass = (param != null ? param.getContainingClass() : null);
//获取的参数的泛型类型
Class<T> targetClass = (targetType instanceof Class<?> ? (Class<T>) targetType : null);
//如果没有就再次尝试设置一遍
if (targetClass == null) {
ResolvableType resolvableType = (param != null ?
ResolvableType.forMethodParameter(param) : ResolvableType.forType(targetType));
targetClass = (Class<T>) resolvableType.resolve();
}
//获取请求方法
HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
Object body = NO_VALUE; try {
inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);
//遍历这个解析器中的所有的converter,判断是否是泛化的转换器
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
//判断是否能够进行解析
if (genericConverter.canRead(targetType, contextClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
}
if (inputMessage.getBody() != null) {
//如果请求体有值,那么就尝试调用实现了RequestAdvice的类,对请求体进行预先处理
inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
//使用converter进行转化
body = genericConverter.read(targetType, contextClass, inputMessage);
//对处理完的body进行后置处理,就是使用实现了ResponseAdvice的类进行处理
body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
}
else {
body = null;
//处理空请求体
body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
}
break;
}
}
//如果不是泛化的转换器,那么就判断目标class是否为空。
else if (targetClass != null) {
if (converter.canRead(targetClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
}
if (inputMessage.getBody() != null) {
inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
}
else {
body = null;
body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
}
break;
}
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex);
}
//如果body没有被处理过
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && inputMessage.getBody() == null)) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
} canRead,判断是否可以处理这个请求类型的数据,对于json来说text/html肯定是不能进行处理的
protected boolean canRead(MediaType mediaType) {
if (mediaType == null) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes()) {
if (supportedMediaType.includes(mediaType)) {
return true;
}
}
return false;
} 解析好后继续
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
//如果指定的参数名为URL,连续两个大写字母的那么就保持它原来的样子,其他的就把第一个字母变成小写,如果是集合类的那么将泛型类型加上list字符串
String name = Conventions.getVariableNameForParameter(parameter);
//创建数据绑定器
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
//对参数进行校验
validateIfApplicable(binder, parameter);
//查看是否发生了异常
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
//抛出参数校验不通过的异常
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
//保存绑定数据后的结果信息
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); return arg;
} public static String getVariableNameForParameter(MethodParameter parameter) {
Assert.notNull(parameter, "MethodParameter must not be null");
Class<?> valueClass;
boolean pluralize = false; if (parameter.getParameterType().isArray()) {
//获取数组的元素类型
valueClass = parameter.getParameterType().getComponentType();
pluralize = true;
}
else if (Collection.class.isAssignableFrom(parameter.getParameterType())) {
//获取集合的泛型参数类型
valueClass = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
if (valueClass == null) {
throw new IllegalArgumentException(
"Cannot generate variable name for non-typed Collection parameter type");
}
//设置为TRUE
pluralize = true;
}
else {
valueClass = parameter.getParameterType();
}
//获取名字,出去包名
String name = ClassUtils.getShortNameAsProperty(valueClass);
//如果pluralize为true,那么就在名字候命加上list字符串
return (pluralize ? pluralize(name) : name);
} @Override
public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
throws Exception {
//创建webdata 绑定
WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
if (this.initializer != null) {
this.initializer.initBinder(dataBinder, webRequest);
}
//开始调用绑定方法
initBinder(dataBinder, webRequest);
return dataBinder;
}
initBinder方法 public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
for (InvocableHandlerMethod binderMethod : this.binderMethods) {
if (isBinderMethodApplicable(binderMethod, binder)) {
//跟前面调用方法是一样的,不过这次传入了一个提供的参数,那就是webDataBinder的实例,所以我们可以在@initBinder方法中添加一些校验器,编辑器等等操作。
Object returnValue = binderMethod.invokeForRequest(request, null, binder);
if (returnValue != null) {
throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
}
}
}
} 创建了webDataBinder之后,并且如果我们在@initBinder注解的方法中做了一些事情,比如添加了校验器啥的,接下来的代码如下
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); //校验
protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) {
Annotation[] annotations = methodParam.getParameterAnnotations();
for (Annotation ann : annotations) {
//只有注释了@valid的参数才会进行校验
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
//获取注解中value值,这些值可以最为校验分组用,SpringMVC的校验使用的JSR303校验和自定义校验器
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
//开始校验
binder.validate(validationHints);
break;
}
}
} //遍历校验器进行校验
public void validate(Object... validationHints) {
for (Validator validator : getValidators()) {
//使用JSR303的方式校验
if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
}
else if (validator != null) {
//使用自定义校验器校验
validator.validate(getTarget(), getBindingResult());
}
}
} 好了,对于RequestBody注解的参数就是这么解析的。 来研究一下ModelAttributeMethodProcessor是怎么解析的 @Override
public boolean supportsParameter(MethodParameter parameter) {
//判断参数是否有@ModelAttribute注解
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
return true;
}
else if (this.annotationNotRequired) {
return !BeanUtils.isSimpleProperty(parameter.getParameterType());
}
else {
return false;
}
} //解析参数
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//获取参数名,先从注解的指定的名称找,如果没有就用Conventions.getVariableNameForParameter(parameter)方法获取参数名,这个在前面就已经使用过了
String name = ModelFactory.getNameForParameter(parameter);
//判断这个参数是否在MavContainer中已经存在了,如果存在就直接获取这个参数值,如果没有找到就去request中寻找参数
Object attribute = (mavContainer.containsAttribute(name) ?
mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, webRequest));
//创建WebDataBinder ,调用@initBinder注解的绑定方法
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
//这里是绑定请求的参数
bindRequestParameters(binder, webRequest);
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
} // Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel); return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
} protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
servletBinder.bind(servletRequest);
} public void bind(ServletRequest request) {
//解析创建成一个MutablePropertyValues
MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
//判断是否为MultipartRequest 类型,如果是就获取这种类型的请求
MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
//获取url中的变量Map用url定义的参数值,如果已经在mpvs存在的参数将不会覆盖
addBindValues(mpvs, request);
//绑定参数
doBind(mpvs);
} //创建MutablePropertyValues时的解析,解析成一个去掉指定前缀的Map,当然这里没有设置前缀
public static Map<String, Object> getParametersStartingWith(ServletRequest request, String prefix) {
Assert.notNull(request, "Request must not be null");
Enumeration<String> paramNames = request.getParameterNames();
Map<String, Object> params = new TreeMap<String, Object>();
if (prefix == null) {
prefix = "";
}
while (paramNames != null && paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
if ("".equals(prefix) || paramName.startsWith(prefix)) {
String unprefixed = paramName.substring(prefix.length());
String[] values = request.getParameterValues(paramName);
if (values == null || values.length == 0) {
// Do nothing, no values found at all.
}
else if (values.length > 1) {
params.put(unprefixed, values);
}
else {
params.put(unprefixed, values[0]);
}
}
}
return params;
} 然后在传入这个paramMap到构造器
public MutablePropertyValues(Map<?, ?> original) {
// We can optimize this because it's all new:
// There is no replacement of existing property values.
if (original != null) {
this.propertyValueList = new ArrayList<PropertyValue>(original.size());
for (Map.Entry<?, ?> entry : original.entrySet()) {
//propertyValueList是一个list,存储着PropertyValue对象,这个对象存着请求参数的名称和对应的值。
this.propertyValueList.add(new PropertyValue(entry.getKey().toString(), entry.getValue()));
}
}
else {
this.propertyValueList = new ArrayList<PropertyValue>(0);
}
} protected void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, MutablePropertyValues mpvs) {
for (Map.Entry<String, List<MultipartFile>> entry : multipartFiles.entrySet()) {
String key = entry.getKey();
List<MultipartFile> values = entry.getValue();
if (values.size() == 1) {
MultipartFile value = values.get(0);
//默认情况下会保存空的MultipartFiles,所以即使你的上传文件框没有上传文件,也会存在空的文件
if (isBindEmptyMultipartFiles() || !value.isEmpty()) {
mpvs.add(key, value);
}
}
else {
mpvs.add(key, values);
}
}
} 开始绑定参数
@Override
protected void doBind(MutablePropertyValues mpvs) {
//检查有default值前缀的参数
checkFieldDefaults(mpvs);
//检查有标记前缀的参数
checkFieldMarkers(mpvs);
真正绑定参数的方法
super.doBind(mpvs);
} checkFieldDefaults方法:
protected void checkFieldDefaults(MutablePropertyValues mpvs) {
//如果字段默认的前缀不为空,那么就去掉前缀,然后判断这个属性在对应的参数对象中是否可写,并且在mpvs中不存在这个属性参会加入到mvps中,并且移除之前的
if (getFieldDefaultPrefix() != null) {
String fieldDefaultPrefix = getFieldDefaultPrefix();
PropertyValue[] pvArray = mpvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
if (pv.getName().startsWith(fieldDefaultPrefix)) {
String field = pv.getName().substring(fieldDefaultPrefix.length());
if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
mpvs.add(field, pv.getValue());
}
mpvs.removePropertyValue(pv);
}
}
}
}
这个方法和上面的是一样的道理
protected void checkFieldMarkers(MutablePropertyValues mpvs) {
if (getFieldMarkerPrefix() != null) {
String fieldMarkerPrefix = getFieldMarkerPrefix();
PropertyValue[] pvArray = mpvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
if (pv.getName().startsWith(fieldMarkerPrefix)) {
String field = pv.getName().substring(fieldMarkerPrefix.length());
if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
Class<?> fieldType = getPropertyAccessor().getPropertyType(field);
mpvs.add(field, getEmptyValue(field, fieldType));
}
mpvs.removePropertyValue(pv);
}
}
}
} 接下来调用了 protected void doBind(MutablePropertyValues mpvs) {
//检查是否是运行的字段,这些字段都可以在@initBinder注解的方法中指定
checkAllowedFields(mpvs);
//判断是否为必须的字段
checkRequiredFields(mpvs);
//应用属性值
applyPropertyValues(mpvs);
} //应用指定的值到对应的对象中
protected void applyPropertyValues(MutablePropertyValues mpvs) {
try {
// Bind request parameters onto target object.
//绑定请求参数到目标参数中
getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
}
catch (PropertyBatchUpdateException ex) {
// Use bind error processor to create FieldErrors.
for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
}
}
} 接下来就是对参数进行类型转换 return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter); public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException { // Custom editor for this type?获取@initBinder注解的方法中自定义的参数编辑器
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName); ConversionFailedException conversionAttemptEx = null; // No custom editor but custom ConversionService specified?
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
try {
//如果可以转换就进行转换
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
conversionAttemptEx = ex;
}
}
} Object convertedValue = newValue;
。。。。。。。。。。。。。。。。。。。。。。。(代码较长,省略) 当所有的参数都解析完毕后,调用方法
Object returnValue = doInvoke(args);
//如果不出例外,就直接使用放射方法调用
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
throw new IllegalStateException(msg, targetException);
}
}
}
handlerAdapter与方法调用(参数的解析)的更多相关文章
- JAVA方法调用中的解析与分派
JAVA方法调用中的解析与分派 本文算是<深入理解JVM>的读书笔记,参考书中的相关代码示例,从字节码指令角度看看解析与分派的区别. 方法调用,其实就是要回答一个问题:JVM在执行一个方法 ...
- Atitit 记录方法调用参数上下文arguments
Atitit 记录方法调用参数上下文arguments 1.1. java java8 新的对象Parameter LocalVariableTable 本地变量表 MethodParamete ...
- 关于Cocos2d-x中addchild和removeChild方法的参数的解析
一.addchild virtual void addchild( Node * child , int localZOrder , int tag )添加一个子节点到容器中,有Z轴顺序和一个标记. ...
- SetACL 使用方法详细参数中文解析
示例: SetACL.exe c:\nihao /dir /deny everyone /read_ex 设置E:\wxDesktop 文件夹 everyone 用户为读取和运行权限 SetACL M ...
- springMVC框架核心方法调用源码解析
- 深入解析多态和方法调用在JVM中的实现
深入解析多态和方法调用在JVM中的实现 1. 什么是多态 多态(polymorphism)是面向对象编程的三大特性之一,它建立在继承的基础之上.在<Java核心技术卷>中这样定义: 一个对 ...
- java类加载机制及方法调用
类加载机制 概述 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading).验证(Verification).准备(Preparation).解析(Resoluti ...
- JVM(十二):方法调用
JVM(十二):方法调用 在 JVM(七):JVM内存结构 中,我们说到了方法执行在何种内存结构上执行:Java 方法活动在虚拟机栈中的栈帧上,栈帧的具体结构在内存结构中已经详细讲解过了,下面就让我们 ...
- Java方法调用机制
最近在编程时,修改方法传入对象的对象引用,并没有将修改反映到调用方法中.奇怪为什么结果没有变化,原因是遗忘了Java对象引用和内存分配机制.本文介绍3个点: ① 该问题举例说明 ② 简要阐述Java内 ...
随机推荐
- mvc中Scripts.Render的用法
第一次接触新的东西,都会很陌生,但是时间久了就熟悉了变简单了. 视图文件中使用Scripts.Render()输出脚本包,Styles.Render()输出样式包 上面两张图是我所做项目里的,放上面会 ...
- 使用回调的方式实现中间件-laravel
$app = function ($request) { echo $request . "\n"; return "项目运行中....."; }; // 现在 ...
- Logback详细整理,基于springboot的日志配置
Logback的配置介绍: 1.Logger.appender及layout Logger作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型.级别. ...
- Windows 10使用Tesseract-OCR出现WindowsError: [Error 2]
Tesseract-OCR安装时默认安装在x86的目录下,手动添加环境变量此电脑-->属性-->高级系统设置-->环境变量,点击系统变量里的Path, 点击编辑,在编辑环境变量界面中 ...
- 一个commit引发的思考
这几天我翻了翻golang的提交记录,发现了一条很有意思的提交:bc593ea,这个提交看似简单,但是引人深思. commit讲了什么 commit的标题是"sync: document i ...
- throw 与 throws的比较
说实话,今天在公司的实习,确确实实编号被严重打脸了,说真的,自己的基础功不扎实,希望慢慢弥补吧! 抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常,下面它们之间的异同. 一 ...
- 并发编程-concurrent指南-线程池ExecutorService的使用
有几种不同的方式来将任务委托给 ExecutorService 去执行: execute(Runnable) submit(Runnable) submit(Callable) invokeAny(… ...
- BZOJ 1061:志愿者招募(单纯型)
题目链接 题意 中文题意. 思路 单纯型模板题. 单纯型用来解决线性规划问题. 留坑待填. 算法思路 好长 模板 论文 卿学姐视频 #include <bits/stdc++.h> usi ...
- cocopods新建或者更新远端库主要操作步骤
1.搭建远程仓库(私有或者公有项目): 2.使用sourceTree拉去远程仓库: 3.打开拉去的项目仓库Finder,构建pod lib项目:pod lib create AFNetworking( ...
- Leetcode 195 Tenth Line
Given a text file file.txt, print just the 10th line of the file. Example: Assume that file.txt has ...