首页 > 其他分享 >【SpringMVC(三)】 HandlerAdapter

【SpringMVC(三)】 HandlerAdapter

时间:2022-11-11 12:36:57浏览次数:45  
标签:return SpringMVC Object request mavContainer HandlerAdapter handler response


HandlerAdapter在springmvc中是一个十分重要的角色。

作用如下:

1.负责直接调用控制器来处理请求;

2.负责在调用控制器的前定制化处理request以及在调用后定制化处理response;

3.隐藏不同类型控制器的调用细节;

下面看一下HandlerAdapter接口:

public interface HandlerAdapter {

/**
* Given a handler instance, return whether or not this {@code HandlerAdapter}
* can support it. Typical HandlerAdapters will base the decision on the handler
* type. HandlerAdapters will usually only support one handler type each.
* <p>A typical implementation:
* <p>{@code
* return (handler instanceof MyHandler);
* }
* @param handler handler object to check
* @return whether or not this object can use the given handler
*/
boolean supports(Object handler);

/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler to use. This object must have previously been passed
* to the {@code supports} method of this interface, which must have
* returned {@code true}.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

/**
* Same contract as for HttpServlet's {@code getLastModified} method.
* Can simply return -1 if there's no support in the handler class.
* @param request current HTTP request
* @param handler handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);

}

其核心方法就是support和handle。

下面从作用3开始说起。什么叫做隐藏不同类型控制器的调用细节?

springmvc中大概有三种控制器类型:

1)直接实现Controller接口;

2)直接实现HttpRequestHandler接口;

3)使用@Controller注解标注;

当然,现在绝大多数场景都是使用第三种,好处是无侵入性,并且支持很多扩展点。

那HandlerAdapter是如何调用控制器的呢?

在DispatcherServlet的doDispatch方法中,有这么一段代码:

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

是根据匹配到的controller来取合适的Adapter的:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

可以看到,取Adapter的过程比较简单,就是从一个list里面一一调用support方法,找到合适的,那么adapters又有哪些那?

一般而言,对应上面的三种控制器,会有三种Adapter。一一看下:

首先是SimpleControllerHandlerAdapter。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}

@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

return ((Controller) handler).handleRequest(request, response);
}

@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}

}

很简单,主要是用来处理实现了Controller接口的控制器,直接调用控制器的handleRequest方法。

第二种是HttpRequestHandlerAdapter。

public class HttpRequestHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}

@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}

@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}

}

也很简单,用来处理实现了HttpRequestHandler接口的控制器。

第三种,也是最常用的一种,RequestMappingHandlerAdapter,用于处理注解类型的控制器,这个比较复杂。重点看下。

首先是support方法:

@Override
public final boolean supports(Object handler) {
return handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler);
}

只处理HandlerMethod类型的控制器。注意,这里对于注解类型的控制器,handler类型就是HandlerMethod。在另一篇有讲。

下面看下RequestMappingHandlerAdapter的处理过程:

@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}

@Override
protected final ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
// Uses configured default cacheSeconds setting.
checkAndPrepare(request, response, true);
}

// 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) {
return invokeHandleMethod(request, response, handlerMethod);
}
}
}

return invokeHandleMethod(request, response, handlerMethod);
}

private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ServletWebRequest webRequest = new ServletWebRequest(request, response);

WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

final 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 + "]");
}
requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
}

requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

return getModelAndView(mavContainer, modelFactory, webRequest);
}

这里createRequestMappingMethod方法负责将之前的handler封装起来:

private ServletInvocableHandlerMethod createRequestMappingMethod(
HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {

ServletInvocableHandlerMethod requestMethod;
requestMethod = new ServletInvocableHandlerMethod(handlerMethod);
requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
requestMethod.setDataBinderFactory(binderFactory);
requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return requestMethod;
}

这里很重要,将Adapter里的两个重要扩展点即argumentResolver和returnValueHandler传入到一个ServletInvocableHandler对象里。最后调用了invokeAndHandle方法:

public final void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

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 {
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;
}
}

这里就两个关键点:一是调用invokeForRequest,二是调用handleReturnValue。

先看下invokeForRequest:

public final 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 = invoke(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());
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.isTraceEnabled()) {
logger.trace(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;
}

invokeForRequest方法先调用argumentResolver处理入参,然后再调用handler。argumentResolver全部被封装在一个HandlerMethodArgumentResolverComposite对象里:

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

protected final Log logger = LogFactory.getLog(getClass());

private final List<HandlerMethodArgumentResolver> argumentResolvers =
new LinkedList<HandlerMethodArgumentResolver>();
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

/**
* Find a registered {@link HandlerMethodArgumentResolver} that supports the given method parameter.
*/
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
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;
}
}

resolve部分其实就是把所有的resolvers过一遍,如果有一个resolver的support返回true,就用该resolver来处理handler的入参。

再看下invoke部分:

private Object invoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
throw new IllegalStateException(getInvocationErrorMessage(ex.getMessage(), 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);
}
}
}

可以看到,handlermethod对象内有controller的方法名,这里通过反射调用controller的方法处理请求。

最后是返回值的处理。handleReturnValue方法是HandlerMethodReturnValueHandlerComposite对象里的方法,该对象封装了所有的HandlerMethodReturnValueHandler对象:

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {

protected final Log logger = LogFactory.getLog(getClass());

private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
new ArrayList<HandlerMethodReturnValueHandler>();


private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
returnType.getGenericParameterType() + "]");
}
if (returnValueHandler.supportsReturnType(returnType)) {
return returnValueHandler;
}
}
return null;
}

@Override
public boolean supportsReturnType(MethodParameter returnType) {
return getReturnValueHandler(returnType) != null;
}

/**
* Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
* @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
*/
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}

这里处理返回值就是一个一个过returnValueHandlers,第一个support返回true的handler来处理返回值。

至此,HandlerAdapter的处理流程基本结束。最后一步就是调用getModelAndView来渲染view。渲染这块准备在另一篇来讲解。

总结:

RequestMappingHandlerAdapter最常用,用来调用注解形式的控制器;具备了处理参数和返回值的能力。通过两个聚合对象聚合了所有的argumentResolver和returnvalueresolver。

标签:return,SpringMVC,Object,request,mavContainer,HandlerAdapter,handler,response
From: https://blog.51cto.com/u_15873544/5844586

相关文章

  • SpringMVC的单文件上传,多文件上传和下载文件(十二)
    你未看此花时,则此花与汝心同归于寂,你来看此花时,此花颜色一时明白起来,便知此花不在你的心外。上一章简单介绍了SpringMVC的数据验证和JSR303国际化显示(十一),如果没有看......
  • SpringMVC概述
    1.SpringMVC是一种基于Java实现MVC模型的轻量级Web框架优点:使用简单,开发便捷(相比于Servlet)灵活性强2.SpringMVC是一种表现层框架技术,用于进行表现层功能开发3. Java......
  • springmvc 整合 camunda
    参考官网:ProcessEngine配置|docs.camunda.org 一POM注意:1低版本c3p0会报错:Methodcom/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z千万记得要删除Ta......
  • 自定义SpringMVC(仅用学习)
    自定义MVC有两大核心:1.AppListener程序一启动,监听器就会对程序进行监听,此时会去获取config从而找到controller路径(在使用web项目时,web.xml需要先配置config信息)、再通......
  • Spring+SpringMVC学习笔记
    Spring学习笔记转载:https://www.yuque.com/kkuping/yuqzh2/vlgfylSpringMVC学习笔记转载:https://www.yuque.com/kkuping/yuqzh2/nxtocy......
  • springMVC+maven+mybatis+Intellij IDEA环境搭建
         之前工作中一直用springMVC和ibatis,现在要从0开始学习maven和mybatis,所以这篇博客就记录我的学习maven,mybatis,intellijIDEA的心路历程。     首......
  • 八、activemq整合springmvc之topic
    一、前言spring代码基于SSM整合(spring-springmvc-mybatis)之CRUD ;代码地址:(基础版本:https://gitee.com/joy521125/ssm-senior-base.gitmaven版:https://gitee.com/joy52......
  • SpringMVC添加依赖包
    `4.0.0<groupId>org.example</groupId><artifactId>ssmbuild</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.com......
  • SpringMVC源码-文件上传
    一、环境配置IndexController.java@GetMapping("/file")publicStringfile(){ return"fileUpload";}@PostMapping("/fileUpload")publicvoidfileUpload(Mul......
  • SpringMVC源码-获取HandleAdapter和调用HandleAdapter.handle
    DispatcherServlet.getHandlerAdapter(Objecthandler)protectedHandlerAdaptergetHandlerAdapter(Objecthandler)throwsServletException{ if(this.handlerAdapt......