为何要讲HandlerInterceptor与HttpMessageConverter异常冲突呢?其实社区也有不少文章讲过(没有讲清楚),很多时候也存在滥用的情况,这里更多是从源码分析他们,并从中学习spring在请求处理这块优秀之处。
目录
基础知识:ServletInvocableHandlerMethod
基础知识:HandlerMethodArgumentResolver
基础知识:HandlerMethodReturnValueHandler
RequestResponseBodyMethodProcessor源码
示例代码
下面提供的示例代码(可能比较复杂),UserSecurityInterceptor对未登陆的进行拦截,ESBMessageConverter主要是对url中存在“*/esb/*”的请求报文进行解析(当请求Controller(public ResponseVO test2(@RequestBody RequestVO requestVO) 它把request body内容(提前部分)填充到的RequestVO中,并把返回的ResponseVO再按某种封装成一个新的VO返回 )。
//这是一个请求拦截器
@Configuration
public class UserSecurityInterceptor extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] securityUrls = new String[]{"/**"};
String[] excludeUrls = new String[]{"/**/esb/**", "/**/dictionary/**"}; registry.addInterceptor(userLoginInterceptor()).addPathPatterns(securityUrls).excludePathPatterns(excludeUrls);
super.addInterceptors(registry);
}
@Bean
public AuthInterceptor userLoginInterceptor() {
return new AuthInterceptor();
}
public class AuthInterceptor implements HandlerInterceptor {
public Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
@Autowired
private ApplicationContext applicationContext;
public AuthInterceptor() {
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
LoginUserInfo user = null;
try {
user = (LoginUserInfo) SSOUserUtils.getCurrentLoginUser();
} catch (Exception e) {
logger.error("从SSO登录信息中获取用户信息失败! 详细错误信息:%s", e);
throw new ServletException("从SSO登录信息中获取用户信息失败!", e);
}
String[] profiles = applicationContext.getEnvironment().getActiveProfiles();
if (!Arrays.isNullOrEmpty(profiles)) {
if ("dev".equals(profiles[0])) {
return true;
}
}
if (user == null || UserUtils.ANONYMOUS_ROLE_ID.equals(user.getRoleId())) {
throw new ServletException("获取登录用户信息失败!");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
}
@Configuration
public class Esbconfig {
@Bean
public JSONMessageConverter jsonMessageConverter(ESBMessageConverter esbMessageConverter, GsonHttpMessageConverter gsonHttpMessageConverter) {
JSONMessageConverter jsonMessageConverter = new JSONMessageConverter();
Map<HttpMessageConverter, List<String>> converterPathMap = new HashMap<>();
List<String> path = new ArrayList<>();
path.add("/**/esb/**");
converterPathMap.put(esbMessageConverter, path);
jsonMessageConverter.setConverterPathMap(converterPathMap);
List<String> swagger = new ArrayList<>();
swagger.add("/");
converterPathMap.put(gsonHttpMessageConverter, swagger);
jsonMessageConverter.setConverterPathMap(converterPathMap);
return jsonMessageConverter;
}
@Bean
public ESBMessageConverter esbMessageConverter(ServerConfiguration serverConfiguration) {
ESBMessageConverter esbMessageConverter = new ESBMessageConverter();
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
esbMessageConverter.setSupportedMediaTypes(mediaTypes);
esbMessageConverter.setObjectMapper(JsonMapperHolder.objectMapper);
esbMessageConverter.setServerConfiguration(serverConfiguration);
return esbMessageConverter;
}
}
//这是一个MessageConverter
public class ESBMessageConverter extends MappingJackson2HttpMessageConverter implements InitializingBean {
public static final Logger ESB_LOGGER = LoggerFactory.getLogger(ESBMessageConverter.class);
private ObjectMapper objectMapper = EntityUtils.OBJECT_MAPPER;
private String jsonPrefix;
private Boolean prettyPrint;
private ServerConfiguration serverConfiguration;
public ESBMessageConverter() {
super();
}
@Override
public void setObjectMapper(final ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.objectMapper = objectMapper;
configurePrettyPrint();
}
private void configurePrettyPrint() {
if (this.prettyPrint != null) {
this.objectMapper.configure(SerializationFeature.INDENT_OUTPUT, this.prettyPrint);
}
}
@Override
public ObjectMapper getObjectMapper() {
return this.objectMapper;
}
@Override
public void setJsonPrefix(final String jsonPrefix) {
this.jsonPrefix = jsonPrefix;
}
@Override
public void setPrefixJson(final boolean prefixJson) {
this.jsonPrefix = prefixJson ? "{} && " : null;
}
@Override
public void setPrettyPrint(final boolean prettyPrint) {
this.prettyPrint = prettyPrint;
configurePrettyPrint();
}
@Override
public boolean canRead(final Class<?> clazz, final MediaType mediaType) {
return canRead(clazz, null, mediaType);
}
@Override
public boolean canRead(final Type type, final Class<?> contextClass, final MediaType mediaType) {
final JavaType javaType = getJavaType(type, contextClass);
return this.objectMapper.canDeserialize(javaType) && canRead(mediaType);
}
@Override
public boolean canWrite(final Class<?> clazz, final MediaType mediaType) {
return this.objectMapper.canSerialize(clazz) && canWrite(mediaType);
}
@Override
protected boolean supports(final Class<?> clazz) {
throw new UnsupportedOperationException();
}
@Override
protected Object readInternal(final Class<?> clazz, final HttpInputMessage inputMessage)
throws IOException {
final JavaType javaType = getJavaType(clazz, null);
return readJavaType(javaType, inputMessage);
}
@Override
public Object read(final Type type, final Class<?> contextClass, final HttpInputMessage inputMessage)
throws IOException {
final JavaType javaType = getJavaType(type, contextClass);
return readJavaType(javaType, inputMessage);
}
private Object readJavaType(final JavaType javaType, final HttpInputMessage inputMessage) {
try {
final Request<Object> request = objectMapper.readValue(inputMessage.getBody(), Request.class);
if (request.getHeader() == null) {
request.setHeader(new RequestHeader());
}
if (ESB_LOGGER.isDebugEnabled()) {
ESB_LOGGER.debug("ESB请求报文为:\n{}", objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(request));
}
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest httpServletRequest;
if (requestAttributes != null) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
httpServletRequest = servletRequestAttributes.getRequest();
httpServletRequest.setAttribute(ESBConstants.ESB_REQUEST, request);
}
return buildRequestBody(javaType, request);
} catch (final IOException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
}
}
private Object buildRequestBody(JavaType javaType, Request<Object> request) throws IOException {
Object obj = request.getBody();
if (obj instanceof List) {
if (javaType.isArrayType()) {
String body = EntityUtils.toJSONString(obj);
return objectMapper.readValue(body, javaType);
}
} else if (obj instanceof Map) {
obj = EntityUtils.map2Bean((Map<String, Object>) request.getBody(), javaType.getRawClass());
}
request.setBody(obj);
if (serverConfiguration.getServerPlugins() != null && !serverConfiguration.getServerPlugins().isEmpty()) {
List<ServerPlugin> serverPlugins = serverConfiguration.getServerPlugins();
for (ServerPlugin serverPlugin : serverPlugins) {
serverPlugin.afterRequest(request);
}
}
return obj;
}
@Override
protected void writeInternal(final Object object, final HttpOutputMessage outputMessage)
throws IOException {
ServletResponse servletResponse = RequestAndResponseContextHolder.response();
if (servletResponse != null) {
servletResponse.setContentType("application/json");
}
final JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
final JsonGenerator jsonGenerator =
this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
if (this.objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
jsonGenerator.useDefaultPrettyPrinter();
}
try {
if (this.jsonPrefix != null) {
jsonGenerator.writeRaw(this.jsonPrefix);
}
final Response response = buildResponse(object);
if (serverConfiguration.getServerPlugins() != null && !serverConfiguration.getServerPlugins().isEmpty()) {
List<ServerPlugin> serverPlugins = serverConfiguration.getServerPlugins();
for (ServerPlugin serverPlugin : serverPlugins) {
serverPlugin.beforeResponse(response);
}
}
if (ESB_LOGGER.isDebugEnabled()) {
ESB_LOGGER.debug("ESB响应报文为:\n{}", EntityUtils.toJSONString(response));
}
this.objectMapper.writeValue(jsonGenerator, response);
} catch (final JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
}
}
/**
* 构造响应消息
*
* @param object
* @return
*/
private Response buildResponse(Object object) {
HttpServletRequest servletRequest = ESBCommonKit.request();
Request request = (Request) servletRequest.getAttribute(ESBConstants.ESB_REQUEST);
RequestHeader requestHeader = request.getHeader();
final Response response = new Response();
final ResponseHeader header = new ResponseHeader();
header.setReqSysCode(requestHeader.getReqSysCode());
header.setServiceCode(requestHeader.getServiceCode());
header.setProviderSysId(serverConfiguration.getProviderSysId());
header.setReturnCode(ResponseHeader.DEFAULT_SUCCESS_CODE);
header.setReturnMessage(null);
header.setSerialNumber(requestHeader.getSerialNumber());
response.setHeader(header);
response.setBody(object);
return response;
}
@Override
protected JavaType getJavaType(final Type type, final Class<?> contextClass) {
return (contextClass != null) ?
this.objectMapper.getTypeFactory().constructType(type, contextClass) :
this.objectMapper.constructType(type);
}
@Override
protected JsonEncoding getJsonEncoding(final MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) {
final Charset charset = contentType.getCharSet();
for (final JsonEncoding encoding : JsonEncoding.values()) {
if (charset.name().equals(encoding.getJavaName())) {
return encoding;
}
}
}
return JsonEncoding.UTF8;
}
public ServerConfiguration getServerConfiguration() {
return serverConfiguration;
}
public void setServerConfiguration(ServerConfiguration serverConfiguration) {
this.serverConfiguration = serverConfiguration;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(serverConfiguration, "请配置ESB接收服务端配置信息");
}
}
HandlerInterceptor
基础知识
在DispatcherServlet中,每个request根据url在HandlerMapping(@RequestMapping的解析)中拿到一个对应处理程序执行链(HandlerExecutionChain,它内部可以定义各种HandlerInterceptor和一个处理器 handler【如:HandlerMethod 】)
Workflow interface that allows for customized handler execution chains. Applications can register any number of existing or custom interceptors for certain groups of handlers, to add common preprocessing behavior without needing to modify each handler implementation.
A HandlerInterceptor gets called before the appropriate HandlerAdapter triggers the execution of the handler itself. This mechanism can be used for a large field of preprocessing aspects, e.g. for authorization checks, or common handler behavior like locale or theme changes. Its main purpose is to allow for factoring out repetitive handler code.
源码
HandlerInterceptor是工作流接口,而它执行在HandlerAdapter(真正处理请求)前后,看源码吧
public interface HandlerInterceptor {
//拦截一个处理程序的执行,在执行HandlerAdapter之前运行
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
//HandlerAdapter执行完之后,但在renders the view之前
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
//请求处理完成后的回调,rendering the view之后
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
//请求执行链
public class HandlerExecutionChain {
//决定HandlerAdapter
private final Object handler;
private HandlerInterceptor[] interceptors;
//执行一组HandlerInterceptor.preHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
//执行一组HandlerInterceptor.postHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
//执行一组HandlerInterceptor.afterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
//执行一组AsyncHandlerInterceptor.afterConcurrentHandlingStarted
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
if (interceptors[i] instanceof AsyncHandlerInterceptor) {
try {
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
}
catch (Throwable ex) {
logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
}
}
}
}
}
}
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取一个HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取一个HandlerAdapter链
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 执行HandlerExecutionChain.applyPreHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//执行请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 执行HandlerExecutionChain.applyPreHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 执行HandlerExecutionChain.triggerAfterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 执行HandlerExecutionChain.triggerAfterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 执行HandlerExecutionChain.triggerAfterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {//异步时
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
}
HttpMessageConverter
如果你可以看懂下面的执行链(response返回的调用链),那基础知识就可以跳过
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:113)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:174)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:247)
at com.kxtx.esb.api.converter.JSONMessageConverter.write(JSONMessageConverter.java:81)
at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:226)
at com.kxtx.esb.api.converter.ESBMessageConverter.writeInternal(ESBMessageConverter.java:199)
基础知识:HandlerAdapter
先获取某个HandlerAdapter,而获取的关键方法supports(判断是否支持适配此handler),它有三个实现:
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
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
//ServletInvocableHandlerMethod下面讲
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 根据HandlerMethod创建WebDataBinder和ServletInvocableHandlerMethod并执行ServletInvocableHandlerMethod
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
}
- HttpRequestHandlerAdapter,认为只要handler属于Controller类型(如:SimpleControllerHandlerAdapter),交由此处理
- SimpleControllerHandlerAdapter,认为只要handler属于HttpRequestHandler类型,交由此处理
- RequestMappingHandlerAdapter,认为只要handler属于HandlerMethod类型,交由此处理
注:handler是从HandlerExecutionChain中获取(前面讲过)
RequestMappingHandlerAdapter通过handleInternal处理用户的请求,它有内部有HandlerMethodReturnValueHandler(输入参数处理,有需要就集成HttpMessageConverter)、HandlerMethodArgumentResolver(输出参数处理,有需要就集成HttpMessageConverter)。而真正的请求时交由ServletInvocableHandlerMethod(InvocableHandlerMethod的子类)处理的。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private HandlerMethodArgumentResolverComposite argumentResolvers;
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
//处理请求
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
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);
}
//执行ServletInvocableHandlerMethod.invokeAndHandle
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
}
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//InvocableHandlerMethod.invokeForRequest
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
}
基础知识:ServletInvocableHandlerMethod
它核心处理逻辑:
- 输入参数处理,包括数据的转换
- 调用 handler method,获取返回参数(使用反射的调用
@RequestMapping
注解的方法) - 处理返回参数,并包装成ModelAndView
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
//MethodReturnValue的集合,也是由RequestMappingHandlerAdapter创建
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
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()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//handle method返回值处理
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
}
public class InvocableHandlerMethod extends HandlerMethod {
// WebDataBinder是由RequestMappingHandlerAdapter.invokeHandlerMethod创建
private WebDataBinderFactory dataBinderFactory;
//MethodArgumentResolver的集合,也是由RequestMappingHandlerAdapter创建
private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "' with arguments " + Arrays.toString(args));
}
Object returnValue = this.doInvoke(args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Method [" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "] returned [" + returnValue + "]");
}
return returnValue;
}
// 核心逻辑,从request中获取入参,然后解析成handler method中的参数
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = this.resolveProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var9) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(this.getArgumentResolutionErrorMessage("Failed to resolve", i), var9);
}
throw var9;
}
} else if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " + parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() + ": " + this.getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
}
return args;
}
}
//HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler的创建
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
//由afterPropertiesSet调用
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()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// 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;
}
//由afterPropertiesSet调用
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
}
基础知识:HandlerMethodArgumentResolver
spring对其支持情况
HandlerMethodArgumentResolver子类 | 注解 or 类 |
RequestParamMapMethodArgumentResolver | @RequestParam |
RequestHeaderMapMethodArgumentResolver | @RequestHeader |
PathVariableMapMethodArgumentResolver | @PathVariable |
ModelAttributeMethodProcessor | @ModelAttribute |
RequestResponseBodyMethodProcessor | @RequestBody |
更多 |
基础知识:HandlerMethodReturnValueHandler
spring对其支持情况
HandlerMethodReturnValueHandler子类 | 注解 or 类 |
---|---|
ModelAndViewMethodReturnValueHandler | ModelAndView |
ModelMethodProcessor | Model |
ViewMethodReturnValueHandler | View |
ResponseBodyEmitterReturnValueHandler | ResponseEntity |
StreamingResponseBodyReturnValueHandler | StreamingResponseBody |
HttpEntityMethodProcessor | HttpEntity |
HttpHeadersReturnValueHandler | HttpHeaders |
CallableMethodReturnValueHandler | 异步Callable |
DeferredResultMethodReturnValueHandler | 异步DeferredResult |
AsyncTaskMethodReturnValueHandler | WebAsyncTask |
ModelAttributeMethodProcessor | @ModelAttribute |
RequestResponseBodyMethodProcessor | @ResponseBody |
ViewNameMethodReturnValueHandler | CharSequence 、void |
MapMethodProcessor | Map |
RequestResponseBodyMethodProcessor源码
比如以@RequestBody注解为例(@ResponseBody同理),最终使用到了RequestResponseBodyMethodProcessor,它先使用HttpMessageConverter序列化,然后使用WebDataBinder(之前讲过)进行验证,验证结果使用BindingResult获取。
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
//调用AbstractHttpMessageConverter.write
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
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 adaptArgumentIfNecessary(arg, parameter);
}
}
HttpMessageConverter源码
对请求及响应进行序列化,看源码吧
public interface HttpMessageConverter<T> {
//判断该转换器是否能将请求内容转换成 Java 对象
boolean canRead(Class<?> var1, MediaType var2);
//判断该转换器是否可以将 Java 对象转换成返回内容
boolean canWrite(Class<?> var1, MediaType var2);
//获得该转换器支持的 MediaType 类型
List<MediaType> getSupportedMediaTypes();
//读取请求内容并转换成 Java 对象
T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;
//将 Java 对象转换后写入返回内容
void write(T var1, MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}
总结
Spring 拦截器(Interceptor)关注执行HandlerAdapter以及渲染页面前后,HttpMessageConverter则关注的是消息的处理,像对 Json 进行加密这样的场景适合用HttpMessageConverter。