springmvc中HandlerAdapter用于執(zhí)行具體的Handler萧恕,也就是controller,是springmvc中一個(gè)特別重要的組件重慢,先來看下接口定義的方法
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
方法的整體邏輯就是解析request的參數(shù),傳遞給handler逊躁,執(zhí)行后拿到結(jié)果后似踱,寫入到response
springmvc內(nèi)置的HandlerAdapter有好幾種,本文來看下最常用的RequestMappingHandlerAdapter,這個(gè)對(duì)象也是在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主要是維護(hù)一些對(duì)請(qǐng)求參數(shù)和響應(yīng)對(duì)象的數(shù)據(jù)處理囚戚,消息轉(zhuǎn)化器messageConverter,參數(shù)解析器argumentResolver轧简,返回值處理器returnValueHandler驰坊,這三者的關(guān)系等下分析
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;
}
這里有個(gè)比較重要的方法configureMessageConverters,用于子類重寫哮独,用于擴(kuò)展messageConverters拳芙,參數(shù)解析器和返回值處理器也是差不多的邏輯,都會(huì)有一個(gè)擴(kuò)展方法皮璧,給應(yīng)用程序添加
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;
}
如果當(dāng)前項(xiàng)目存在Jackson舟扎,那么還會(huì)添加兩個(gè)BodyAdvice,分別為JsonViewRequestBodyAdvice和JsonViewResponseBodyAdvice恶导,這個(gè)在后面的工作流程再介紹這兩者的作用
當(dāng)生成bean對(duì)象后浆竭,由于RequestMappingHandlerAdaptor也實(shí)現(xiàn)了InitializingBean接口,所以還會(huì)執(zhí)行初始化方法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方法就是查詢?nèi)萜髦凶⒔饬薂ControllerAdvice的類邦泄,然后根據(jù)三種情況進(jìn)行處理,如下
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的裂垦,會(huì)維護(hù)到HandlerAdapter的成員屬性中
if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
到這邊顺囊,RequestMappingHandlerAdapter實(shí)例化和初始化完成了,然后添加到spring容器中蕉拢,需要特別注意的是argumentResolvers 特碳、returnValueHandlers 、messageConverters 晕换、@ControllerAdvice午乓,這幾個(gè)在執(zhí)行handler過程中發(fā)揮了核心作用。
下面以一個(gè)實(shí)際的例子來跟蹤下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;
}
當(dāng)有請(qǐng)求到來時(shí)闸准,會(huì)先經(jīng)過DispatcherServlet的doDispatch方法益愈,然后HandMapping會(huì)拿到了HandlerExecutionChain對(duì)象,接著springmvc會(huì)拿到一個(gè)HandlerAdapter來執(zhí)行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));
}
當(dāng)拿到RequestMappingHandlerAdaptor對(duì)象后夷家,便根據(jù)request執(zhí)行具體的HandlerMethod了
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
一直跟進(jìn)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);
}
//結(jié)果容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//根據(jù)webRequest 執(zhí)行invocableMethod,然后將結(jié)果存儲(chǔ)在mavContainer 中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
這個(gè)方法省略了很多源碼库快,暫時(shí)先不考慮InitBinder和ModelAttribute摸袁,只關(guān)注最核心部分
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會(huì)根據(jù)argumentResolvers解析http的請(qǐng)求輸入流,轉(zhuǎn)成Controller方法需要的參數(shù)列表义屏,然后根據(jù)拿到的參數(shù)執(zhí)行方法靠汁,返回結(jié)果
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//獲取參數(shù)列表
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
return doInvoke(args);
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//根據(jù)HandlerMethod拿到對(duì)應(yīng)的參數(shù)列表蜂大,若為空,則返回
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
//循環(huán)parameters蝶怔,獲取每個(gè)參數(shù)值
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
//若argumentResolvers沒有一個(gè)能支持解析當(dāng)前parameter县爬,便會(huì)拋異常
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//若支持了,再根據(jù)解析器進(jìn)行參數(shù)值的解析并獲取
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
}
}
return args;
}
先來看下判斷解析器是否能解析當(dāng)前參數(shù)的邏輯
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;
}
會(huì)先從緩存獲取添谊,緩存不為null,直接返回察迟,為空斩狱,再循環(huán)每個(gè)resolver,拿到支持解析的resolver后加入緩存便返回
上面這個(gè)例子中扎瓶,參數(shù)是用@RequestBody注解的所踊,因此最終會(huì)有這個(gè)解析器RequestResponseBodyMethodProcessor,判斷的邏輯也很簡單概荷,就是看參數(shù)是否有@RequestBody注解,因此接下來秕岛,看下這個(gè)解析器對(duì)參數(shù)的處理過程
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對(duì)參數(shù)的解析實(shí)際上是通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;
}
這個(gè)方法的執(zhí)行步驟
- 獲取messageConverter继薛,執(zhí)行canRead方法,判斷是否可以從http請(qǐng)求讀取數(shù)據(jù)
- 執(zhí)行注解了@ControllerAdvice的RequestBodyAdvice類的beforeBodyRead方法
- 執(zhí)行messageConverter的read方法愈捅,獲取請(qǐng)求參數(shù)對(duì)象
- 執(zhí)行注解了@ControllerAdvice的RequestBodyAdvice類的afterBodyRead方法
看到這遏考,便可知道,若程序要在請(qǐng)求數(shù)據(jù)達(dá)到controller前做一些處理蓝谨,可以通過三個(gè)地方來實(shí)現(xiàn)灌具,也就是上述的2、3譬巫、4個(gè)步驟咖楣。這個(gè)在一些特殊場(chǎng)景是很有用的,比如前端數(shù)據(jù)要做一些加密芦昔,然后再后端controller接收到時(shí)希望是明文的诱贿,便可這樣處理。
當(dāng)參數(shù)解析器根據(jù)http請(qǐng)求解析出參數(shù)對(duì)象后烟零,執(zhí)行controller的方法瘪松,獲取到結(jié)果,會(huì)執(zhí)行returnValueHandler的handleReturnValue锨阿,需要將結(jié)果寫入到http的輸出流當(dāng)中
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;
}
最終會(huì)找到這個(gè)RequestResponseBodyMethodProcessor宵睦,內(nèi)部也是通過messageConverter將數(shù)據(jù)寫入到http輸出流的,根據(jù)方法墅诡,會(huì)看到這個(gè)邏輯
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;
}
}
}
這里重點(diǎn)關(guān)注下這幾個(gè)步驟
- 根據(jù)messageConverter壳嚎,判斷canWrite方法桐智,若返回true
- 執(zhí)行注解了@ControllerAdvice的ResponseBodyAdvice的beforeBodyWrite方法
- 執(zhí)行messageConverter的write方法
這里也需要注意的一個(gè)是,程序可以通過在beforeBodyWrite方法內(nèi)對(duì)返回對(duì)象做一些處理烟馅,修改數(shù)據(jù)说庭,然后再寫入到http輸出流當(dāng)中。
總結(jié)郑趁,HandlerAdapter最主要的三個(gè)屬性值刊驴,argumentResolver,messageConverter寡润,returnValueHandler捆憎,argumentResolver內(nèi)部使用messageConverter將http輸入流數(shù)據(jù)轉(zhuǎn)成controller對(duì)應(yīng)的參數(shù)對(duì)象,然后執(zhí)行controller的方法梭纹,拿到controller方法返回的結(jié)果后躲惰,returnValueHandler內(nèi)部使用messageConverter將controller返回的結(jié)果寫入到http輸出流中
還有個(gè)要注意的地方便是可以通過RequestBodyAdvice和ResponseBodyAdvice對(duì)請(qǐng)求和響應(yīng)做一些特殊處理。