HandlerAdapters
HandlerAdapter是处理器适配器,Spring MVC通过HandlerAdapter来实际调用处理函数。它是SpringMvc处理流程的第二步,当HandlerMapping获取了定位请求处理器Handler,DispatcherServlet会将得到的Handler告知HandlerAdapter,HandlerAdapter再根据请求去定位请求的具体处理方法是哪一个。
流程
-
DispatcherServlte会根据配置文件信息注册HandlerAdapter,如果在配置文件中没有配置,那么 DispatcherServlte会获取HandlerAdapter的默认配置,如果是读取默认配置的话,DispatcherServlte会读取 DispatcherServlte.properties文件,该文件中配置了三种 HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和 AnnotationMethodHandlerAdapter。DispatcherServlte会将这三个HandlerAdapter对象存储到 它的handlerAdapters这个集合属性中,这样就完成了HandlerAdapter的注册。
-
DispatcherServlte会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter 一一匹配,看哪一种HandlerAdapter是支持该controller类型的,如果找到了其中一种HandlerAdapter是支持传过来的 controller类型,那么该HandlerAdapter会调用自己的handle方法,handle方法运用Java的 反射机制执行controller的具体方法来获得ModelAndView,例如SimpleControllerHandlerAdapter是支持 实现了controller接口的控制器,如果自己写的控制器实现了controller接口,那么 SimpleControllerHandlerAdapter就会去执行自己写控制器中的具体方法来完成请求。
作用
-
HandlerAdapter定义了如何处理请求的策略,通过请求url、请求Method和处理器的requestMapping定义,最终确定使用处理类的哪个方法来处理请求,并检查处理类相应处理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView。
-
DispatcherServlet中根据HandlerMapping找到对应的handler method后,首先检查当前工程中注册的所有可用的handlerAdapter,根据handlerAdapter中的supports方法找到可以使用的handlerAdapter。
-
通过调用handlerAdapter中的handler方法来处理及准备handler method的参数及annotation(这就是spring mvc如何将request中的参数变成handle method中的输入参数的地方),最终调用实际的handler method。
初始化
与initHandlerMappings的处理一致,读取DispatcherServlet.properties中的HandlerAdapters,但不是通过后置处理器触发
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// 从应用上下文中查找HandlerAdapter
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
} else {
try {
//如果在web.xml配了detectAllHandlerAdapters=false,此时spring会加载名称为handlerAdapter的bean为处理器适配器
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
// 转化为集合赋给handlerAdapters属性
this.handlerAdapters = Collections.singletonList(ha);
} catch (NoSuchBeanDefinitionException ex) {
}
}
//如果未配置,读取DispatcherServlet.properties中的HandlerAdapters,放入this.handlerAdapters
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
DispatcherServlet的doDispatch方法会遍历handlerAdapters,找到handler对应的适配器
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");
}
HandlerAdapter的接口中定义了三个方法:
(1)boolean supports(Object handler); 判断适配器是否适配Handler
(2)ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 使用适配的Handler处理用户请求
(3)long getLastModified(HttpServletRequest request, Object handler); 返回资源的最后修改时间,如果handler实现类不支持可以返回-1
SimpleServletHandlerAdapter
SimpleSerlvetHandlerAdapter是Spring使用HandlerAdapter最简单的方式,此方式是为了在Spring中支持Servlet方式开发,即把Servlet适配为处理器handler。
是一个Servlet的适配器,其最终执行的方法是Servlet的service方法,非默认提供(DispatcherServlet.properties中没有)
需要自己导入bean
supports方法就是判断handler是否是Servlet
getLastModified直接返回-1
handle方法本质是执行Servlet.service方法。
public class SimpleServletHandlerAdapter implements HandlerAdapter {
//判断handler是否实现Servlet接口
@Override
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
SimpleControllerHandlerAdapter
是Controller实现类的适配器类,其本质是执行Controller中的handleRequest方法。
supports方法就是判断handler是否是Controller
getLastModified直接返回-1
handle方法本质是执行Controller.handleRequest方法。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
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;
}
}
HttpRequestHandlerAdapter
supports方法就是判断handler是否是HttpRequestHandler
getLastModified直接返回-1
handle方法本质是执行HttpRequestHandler.handleRequest方法。
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
//判断是否是HttpRequestHandler子类
return (handler instanceof HttpRequestHandler);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//执行HttpRequestHandler的handleRequest方法
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
//返回modified值
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
RequestMappingHandlerAdapter
通过继承抽象类AbstractHandlerMethodAdapter实现了HandlerAdapter接口
请求适配给@RequestMapping
类型的Handler处理。
采用反射机制调用url请求对应的Controller中的方法(这其中还包括参数处理),返回执行结果值,完成HandlerAdapter的使命
getLastModified直接返回-1
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
//通过父类调用
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// 判断当前是否需要支持在同一个session中只能线性地处理请求
if (this.synchronizeOnSession) {
// 获取当前请求的session对象
HttpSession session = request.getSession(false);
if (session != null) {
// 为当前session生成一个唯一的可以用于锁定的key
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 对HandlerMethod进行参数等的适配处理,并调用目标handler
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 如果当前不存在session,则直接对HandlerMethod进行适配
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理,为其设置过期时间
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
// 如果当前SessionAttribute中存在配置的attributes,则为其设置过期时间。
// 这里SessionAttribute主要是通过@SessionAttribute注解生成的
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
// 如果当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,
// 如果存在,则按照该设置进行response处理,如果不存在,则设置response中的
// Cache的过期时间为-1,即立即失效
prepareResponse(response);
}
}
return mav;
}
//核心处理流程
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中配置的InitBinder,用于进行参数的绑定
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller
// 中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 将handlerMethod封装为一个ServletInvocableHandlerMethod对象,该对象用于对当前request的整体调用流程进行了封装
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 设置当前容器中配置的所有ArgumentResolver
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 设置当前容器中配置的所有ReturnValueHandler
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 将前面创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
invocableMethod.setDataBinderFactory(binderFactory);
// 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 这里initModel()方法主要作用是调用前面获取到的@ModelAttribute标注的方法,
// 从而达到@ModelAttribute标注的方法能够在目标Handler调用之前调用的目的
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 获取当前的AsyncWebRequest,这里AsyncWebRequest的主要作用是用于判断目标
// handler的返回值是否为WebAsyncTask或DefferredResult,如果是这两种中的一种,
// 则说明当前请求的处理应该是异步的。所谓的异步,指的是当前请求会将Controller中
// 封装的业务逻辑放到一个线程池中进行调用,待该调用有返回结果之后再返回到response中。
// 这种处理的优点在于用于请求分发的线程能够解放出来,从而处理更多的请求,只有待目标任务
// 完成之后才会回来将该异步任务的结果返回。
AsyncWebRequest asyncWebRequest = WebAsyncUtils
.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 封装异步任务的线程池,request和interceptors到WebAsyncManager中
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 + "]");
}
// 封装异步任务的处理结果,虽然封装的是一个HandlerMethod,但只是Spring简单的封装
// 的一个Callable对象,该对象中直接将调用结果返回了。这样封装的目的在于能够统一的
// 进行右面的ServletInvocableHandlerMethod.invokeAndHandle()方法的调用
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,
// 还会判断是否需要将FlashAttributes封装到新的请求中
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
// 调用request destruction callbacks和对SessionAttributes进行处理
webRequest.requestCompleted();
}
}
获取当前容器中使用@InitBinder
注解注册的属性转换器;
获取当前容器中使用@ModelAttribute
标注但没有使用@RequestMapping
标注的方法,并且在调用目标方法之前调用这些方法;
判断目标handler返回值是否使用了WebAsyncTask或DefferredResult封装,如果封装了,则按照异步任务的方式进行执行;
处理请求参数,调用目标方法和处理返回值。