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
posted on 2016-03-23 18:10  liaozq  阅读(341)  评论(0编辑  收藏  举报