springmvc中HandlerAdapter用于执行具体的Handler,也就是controller,是springmvc中一个特别重要的组件,先来看下接口定义的方法
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
方法的整体逻辑就是解析request的参数,传递给handler,执行后拿到结果后,写入到response
springmvc内置的HandlerAdapter有好几种,本文来看下最常用的RequestMappingHandlerAdapter,这个对象也是在spring容器初始化后便完成了,定义在WebMVCConfigurationSupport中
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(contentNegotiationManager);
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
adapter.setCustomArgumentResolvers(getArgumentResolvers());
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
configureAsyncSupport(configurer);
if (configurer.getTaskExecutor() != null) {
adapter.setTaskExecutor(configurer.getTaskExecutor());
}
if (configurer.getTimeout() != null) {
adapter.setAsyncRequestTimeout(configurer.getTimeout());
}
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
return adapter;
}
从这可以看出HandlerAdapter主要是维护一些对请求参数和响应对象的数据处理,消息转化器messageConverter,参数解析器argumentResolver,返回值处理器returnValueHandler,这三者的关系等下分析
protected final List<HttpMessageConverter<?>> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
addDefaultHttpMessageConverters(this.messageConverters);
}
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
这里有个比较重要的方法configureMessageConverters,用于子类重写,用于扩展messageConverters,参数解析器和返回值处理器也是差不多的逻辑,都会有一个扩展方法,给应用程序添加
protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
if (this.argumentResolvers == null) {
this.argumentResolvers = new ArrayList<>();
addArgumentResolvers(this.argumentResolvers);
}
return this.argumentResolvers;
}
protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
if (this.returnValueHandlers == null) {
this.returnValueHandlers = new ArrayList<>();
addReturnValueHandlers(this.returnValueHandlers);
}
return this.returnValueHandlers;
}
如果当前项目存在Jackson,那么还会添加两个BodyAdvice,分别为JsonViewRequestBodyAdvice和JsonViewResponseBodyAdvice,这个在后面的工作流程再介绍这两者的作用
当生成bean对象后,由于RequestMappingHandlerAdaptor也实现了InitializingBean接口,所以还会执行初始化方法afterPropertiesSet
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);
}
}
其中,initControllerAdviceCache方法就是查询容器中注解了@ControllerAdvice的类,然后根据三种情况进行处理,如下
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
//查找注解了@ControllerAdvice的bean列表
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);
}
//查询bean中是否有注解@ModelAttribute的方法
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
}
//查询bean中是否有注解@InitBinder的方法
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
//如果该类是RequestBodyAdvice或者ResponseBodyAdvice的,会维护到HandlerAdapter的成员属性中
if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
到这边,RequestMappingHandlerAdapter实例化和初始化完成了,然后添加到spring容器中,需要特别注意的是argumentResolvers 、returnValueHandlers 、messageConverters 、@ControllerAdvice,这几个在执行handler过程中发挥了核心作用。
下面以一个实际的例子来跟踪下RequestMappingHandlerAdapter的工作流程
@ResponseBody
@RequestMapping(method = RequestMethod.POST, value = "/getStudent")
public GetStudentResp getStudent(@RequestBody GetStudentParam param) {
Student student = new Student();
student.setName("hello" + param.getUserId());
GetStudentResp resp = new GetStudentResp();
resp.setStudent(student);
return resp;
}
当有请求到来时,会先经过DispatcherServlet的doDispatch方法,然后HandMapping会拿到了HandlerExecutionChain对象,接着springmvc会拿到一个HandlerAdapter来执行HandlerExecutionChain的HandlerMethod
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
当拿到RequestMappingHandlerAdaptor对象后,便根据request执行具体的HandlerMethod了
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
一直跟进handle方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//将HandlerMethod包装成ServletInvocableHandlerMethod ,并添加argumentResolvers 和returnValueHandlers
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//结果容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//根据webRequest 执行invocableMethod,然后将结果存储在mavContainer 中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
这个方法省略了很多源码,暂时先不考虑InitBinder和ModelAttribute,只关注最核心部分
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
invokeForRequest会根据argumentResolvers解析http的请求输入流,转成Controller方法需要的参数列表,然后根据拿到的参数执行方法,返回结果
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取参数列表
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
return doInvoke(args);
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//根据HandlerMethod拿到对应的参数列表,若为空,则返回
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
//循环parameters,获取每个参数值
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
//若argumentResolvers没有一个能支持解析当前parameter,便会抛异常
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//若支持了,再根据解析器进行参数值的解析并获取
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
}
}
return args;
}
先来看下判断解析器是否能解析当前参数的逻辑
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
会先从缓存获取,缓存不为null,直接返回,为空,再循环每个resolver,拿到支持解析的resolver后加入缓存便返回
上面这个例子中,参数是用@RequestBody注解的,因此最终会有这个解析器RequestResponseBodyMethodProcessor,判断的逻辑也很简单,就是看参数是否有@RequestBody注解,因此接下来,看下这个解析器对参数的处理过程
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
return adaptArgumentIfNecessary(arg, parameter);
}
很清晰的看出,resolver对参数的解析实际上是通messageConverter来完成的,也就是在HandlerAdapter初始化过程中添加的converter
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
Class<?> contextClass = parameter.getContainingClass();
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
}
else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
return body;
}
这个方法的执行步骤
- 获取messageConverter,执行canRead方法,判断是否可以从http请求读取数据
- 执行注解了@ControllerAdvice的RequestBodyAdvice类的beforeBodyRead方法
- 执行messageConverter的read方法,获取请求参数对象
- 执行注解了@ControllerAdvice的RequestBodyAdvice类的afterBodyRead方法
看到这,便可知道,若程序要在请求数据达到controller前做一些处理,可以通过三个地方来实现,也就是上述的2、3、4个步骤。这个在一些特殊场景是很有用的,比如前端数据要做一些加密,然后再后端controller接收到时希望是明文的,便可这样处理。
当参数解析器根据http请求解析出参数对象后,执行controller的方法,获取到结果,会执行returnValueHandler的handleReturnValue,需要将结果写入到http的输出流当中
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
最终会找到这个RequestResponseBodyMethodProcessor,内部也是通过messageConverter将数据写入到http输出流的,根据方法,会看到这个逻辑
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
}
return;
}
}
}
这里重点关注下这几个步骤
- 根据messageConverter,判断canWrite方法,若返回true
- 执行注解了@ControllerAdvice的ResponseBodyAdvice的beforeBodyWrite方法
- 执行messageConverter的write方法
这里也需要注意的一个是,程序可以通过在beforeBodyWrite方法内对返回对象做一些处理,修改数据,然后再写入到http输出流当中。
总结,HandlerAdapter最主要的三个属性值,argumentResolver,messageConverter,returnValueHandler,argumentResolver内部使用messageConverter将http输入流数据转成controller对应的参数对象,然后执行controller的方法,拿到controller方法返回的结果后,returnValueHandler内部使用messageConverter将controller返回的结果写入到http输出流中
还有个要注意的地方便是可以通过RequestBodyAdvice和ResponseBodyAdvice对请求和响应做一些特殊处理。