HandlerAdapter组件是一个处理器Handler的适配器。HandlerAdapter组件的主要作用是适配特定的Handler来处理相应的请求。
在SpringMvc的源码中, HandlerAdapter是一个接口。该接口主要定义了三个方法。
1.boolean supports(Object handler)
判断HandlerAdapter组件是否支持这个handler实例。
2.ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
HandlerAdapter组件使用handler实例来处理具体的请求。
3.long getLastModified(HttpServletRequest request, Object handler)
获取资源的最后修改值,该方法已经被遗弃。
从以上类图中可以看出, HandlerAdapter接口系列的继承结构是比较简单的。HandlerFunctionAdapter,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,SimpleServletHandlerAdapter这四个类直接继承了HandlerAdapter接口。只有RequestMappingHandlerAdapter类稍微复杂一些。RequestMappingHandlerAdapter类是间接继承了HandlerAdapter这个接口。RequestMappingHandlerAdapter类首先是继承了AbstractHandlerMethodAdapter这个抽象类,而AbstractHandlerMethodAdapter这个抽象类再继承了HandlerAdapter接口。
AbstractHandlerMethodAdapter是一个抽象类,它继承了HandlerAdapter接口,分别实现了HandlerAdapter接口的supports,handle,getLastModified这三个方法。
getLastModified方法已经弃用,就不多做描述。
supports方法
- @Override
-
- public final boolean supports(Object handler) {
-
- return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
-
- }
supports方法主要是判断该适配器是否支持这个handler。代码中的逻辑主要是判断handler是否是HandlerMethod类的实例,再综合了supportsInternal方法的返回值。
supportsInternal方法在AbstractHandlerMethodAdapter类中只是一个虚方法,主要是提供给子类RequestMappingHandlerAdapter来做具体的实现。
- @Override
-
- @Nullable
-
- public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
-
- throws Exception {
-
-
-
- return handleInternal(request, response, (HandlerMethod) handler);
-
- }
在handle方法中,又直接调用了handleInternal方法。handleInternal方法在AbstractHandlerMethodAdapter类中也只是一个虚方法的声明,专门是提供给子类来实现,handleInternal这个虚方法,最终是在RequestMappingHandlerAdapter类中给出了具体的逻辑实现。
AbstractHandlerMethodAdapter实现了Ordered接口。该接口主要是用于排序。
AbstractHandlerMethodAdapter还继承了WebContentGenerator类,该类是一个web内容生成器的超类,它提供了如浏览器缓存控制、是否必须有session开启、支持的请求方法类型(GET、POST等)等一些属性和方法。
WebContentGenerator中有个checkRequest方法,主要是对请求进行检测。子类RequestMappingHandlerAdapter中会调用这个方法。
Spring MVC容器在初始化HandlerAdapter类型的组件时,默认初始化的就是RequestMappingHandlerAdapter这个组件。
RequestMappingHandlerAdapter除了继承至AbstractHandlerMethodAdapter这个父类,它还实现了InitializingBean和BeanFactoryAware接口。
我们知道在Spring中如果一个类实现了InitializingBean接口,Spring容器就会在实例化该Bean时,会调用这个Bean的afterPropertiesSet方法。
- @Override
-
- public void afterPropertiesSet() {
-
- // Do this first, it may add ResponseBody advice beans
-
- initControllerAdviceCache();
-
-
-
- if (this.argumentResolvers == null) {
-
- List
resolvers = getDefaultArgumentResolvers(); -
- this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
-
- }
-
- if (this.initBinderArgumentResolvers == null) {
-
- List
resolvers = getDefaultInitBinderArgumentResolvers(); -
- this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
-
- }
-
- if (this.returnValueHandlers == null) {
-
- List
handlers = getDefaultReturnValueHandlers(); -
- this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
-
- }
-
- }
在RequestMappingHandlerAdapter类中的afterPropertiesSet方法中,主要做了以下四件事情。
1.initControllerAdviceCache方法主要是初始化RequestMappingHandlerAdapter类中,initBinderAdviceCache,modelAttributeAdviceCache, requestResponseBodyAdvice这三个属性。
在initControllerAdviceCache方法中会首先在Spring容器中,获取所带有@ControllerAdvice注解的bean。
然后依次遍历每个bean,在每个bean查找有@InitBinder注解的方法,再将这些方法初始化initBinderAdviceCache这个属性。
再次查找每个bean中有@ModelAttribute注解的方法,再将这些方法初始化到modelAttributeAdviceCache这个属性。
将实现了RequestBodyAdvice接口和ResponseBodyAdvice接口的bean,先收集起来。最后放入requestResponseBodyAdvice这个属性列表的最前面。
2.初始化RequestMappingHandlerAdapter类的argumentResolvers属性。
在RequestMappingHandlerAdapter类的argumentResolvers属性为空的情况下,会调用getDefaultArgumentResolvers()方法,来构造默认解析器的列表。
解析器的列表是按照注释解析,类型解析,自定义解析,所有类型解析的四种类型的顺序来进行构造的。
3.初始化RequestMappingHandlerAdapter类的initBinderArgumentResolvers属性。
在RequestMappingHandlerAdapter类的initBinderArgumentResolvers属性为空的情况下,会调用getDefaultInitBinderArgumentResolvers ()方法,来构造默认解析器的列表。
解析器的列表同样是按照”注释解析”, ”类型解析”, ”自定义解析”, ”所有类型解析”这四种类型的顺序来进行构造。
4.初始化RequestMappingHandlerAdapter类的returnValueHandlers属性,在RequestMappingHandlerAdapter类的returnValueHandlers属性为空的情况下,会调用getDefaultReturnValueHandlers ()方法,来构造默认解析器的列表。
解析器的列表是按照”单个意图”, ”注释解析”, ”多个意图”, ”类型解析”, ”自定义解析”, ”所有类型解析”等这几种类型的顺序来进行构造的。
RequestMappingHandlerAdapter继承了AbstractHandlerMethodAdapter类,它主要重写了父类AbstractHandlerMethodAdapter提供的三个模板方法。
1.supportsInternal方法
在supportsInternal方法中,直接返回了true。所以真正起作用的还是父类中的supports方法。
2.getLastModifiedInternal方法
该方法直接返回了-1。
3.handleInternal方法
这个方法是实际处理请求的方法。整个方法大致分了三个步骤。
- 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
-
- mav = invokeHandlerMethod(request, response, handlerMethod);
-
- }
-
- }
-
- else {
-
- // No synchronization on session demanded at all...
-
- mav = invokeHandlerMethod(request, response, handlerMethod);
-
- }
-
-
-
- if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
-
- if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
-
- applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
-
- }
-
- else {
-
- prepareResponse(response);
-
- }
-
- }
-
-
-
- return mav;
-
- }
从以上代码中可以看出,handleInternal的方法中主要是调用了checkRequest,invokeHandlerMethod等这几个方法。
checkRequest方法主要是对请求进行检测。RequestMappingHandlerAdapter类的
checkRequest方法其实调用的是父类WebContentGenerator的checkRequest方法。
在checkRequest方法中,主要是做了两个检测。
1.首先会用request和response构建一个ServletWebRequest对象。
2.构建一个WebDataBinderFactory对象
3.构建一个ModelFactory对象
4.创建一个ServletInvocableHandlerMethod的实例,实际请求的处理就是通过它来执行的。ServletInvocableHandlerMethod实例创建后,会把argumentResolvers,returnValueHandlers,parameterNameDiscoverer这些属性值赋值给这个实例。
ServletInvocableHandlerMethod实例处理请求使用的是invokeAndHandle方法。在invokeAndHandle方法中,会先调用父类的invokeForRequest方法。再对Response的状态进行设置,最后使用HandlerMethodReturnValueHandler来处理返回值。
在invokeForRequest方法中,会先使用getMethodArgumentValues这个方法来获取方法调用的所有参数。再调用doInvoke(args)方法。doInvoke(args)方法是实际执行请求处理的方法,它是HandlerMethod系列的最核心的方法。在doInvoke(args)方法中,通过getBridgedMethod()获取Method的桥方法。再利用java的反射技术,调用BridgedMethod的invoke(getBean(), args)方法,将具体的handler执行。
在RequestMappingHandlerAdapter类中,通过getDataBinderFactory方法,创建了一个WebDataBinderFactory类型的实例。
- private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
-
- Class> handlerType = handlerMethod.getBeanType();
-
- Set
methods = this.initBinderCache.get(handlerType); -
- if (methods == null) {
-
- methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
-
- this.initBinderCache.put(handlerType, methods);
-
- }
-
- List
initBinderMethods = new ArrayList<>(); -
- // Global methods first
-
- this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
-
- if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
-
- Object bean = controllerAdviceBean.resolveBean();
-
- for (Method method : methodSet) {
-
- initBinderMethods.add(createInitBinderMethod(bean, method));
-
- }
-
- }
-
- });
-
- for (Method method : methods) {
-
- Object bean = handlerMethod.getBean();
-
- initBinderMethods.add(createInitBinderMethod(bean, method));
-
- }
-
- return createDataBinderFactory(initBinderMethods);
-
- }
在getDataBinderFactory方法中,会先通过handlerMethod所属bean类型,查找带有@InitBinder注解的方法。
这里使用了initBinderCache缓存,一般是先在缓存中查找,在找不到的情况下,再通过MethodIntrospector.selectMethods方法去查找。最后把查找到的methods放入到缓存中。
在initBinderAdviceCache缓存中,缓存的是全局的@InitBinder注解的方法。所谓全局的方法就是@ControllerAdvice注解类里面的@InitBinder注解的方法。
代码中会先将全局的method构建成InvocableHandlerMethod对象放入initBinderMethods的集合中。再将handlerMethod所属bean类型的method放入集合。最后通过initBinderMethods集合,来创建一个ServletRequestDataBinderFactory对象。
WebDataBinderFactory是一个工厂类,专门用来创建DataBinder类型的对象。DataBinder类型的对象用于参数绑定,主要功能就是实现参数跟String之间的类型转换,ArgumentResolver在进行参数解析的过程中会用到WebDataBinder,另外ModelFactory在更新Model时也会用到它。
在RequestMappingHandlerAdapter类中,通过getModelFactory方法,创建了一个ModelFactory类型的实例。
- private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
-
- SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
-
- Class> handlerType = handlerMethod.getBeanType();
-
- Set
methods = this.modelAttributeCache.get(handlerType); -
- if (methods == null) {
-
- methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
-
- this.modelAttributeCache.put(handlerType, methods);
-
- }
-
- List
attrMethods = new ArrayList<>(); -
- // Global methods first
-
- this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
-
- if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
-
- Object bean = controllerAdviceBean.resolveBean();
-
- for (Method method : methodSet) {
-
- attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
-
- }
-
- }
-
- });
-
- for (Method method : methods) {
-
- Object bean = handlerMethod.getBean();
-
- attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
-
- }
-
- return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
-
- }
ModelFactory类型实例的创建和WebDataBinderFactory的创建过程十分类似。都是先在handlerMethod所属bean类型查找@ModelAttribute注解的局部方法。再从modelAttributeAdviceCache缓存中,查找全局的@ModelAttribute注解的方法。
将全局和局部的@ModelAttribute注解方法,组合起来形成一个HandlerMothed的列表。全局的@ModelAttribute注解方法会放在这个列表的前面。
ModelFactory与WebDataBinderFactory的创建过程不同的是,多了一个SessionAttributesHandler实例的获取。最后会把HandlerMothed的列表,SessionAttributesHandler的实例和binderFactory作为参数,来构建ModelFactory的实例。
ModelFactory类是专门用来维护Model的。他主要做了两件事件。
initModel方法主要是在处理器Handler执行前,将相应的数据设置到Model中。
- public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
-
- throws Exception {
-
-
-
- Map
sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request); -
- container.mergeAttributes(sessionAttributes);
-
- invokeModelAttributeMethods(request, container);
-
-
-
- for (String name : findSessionAttributeArguments(handlerMethod)) {
-
- if (!container.containsAttribute(name)) {
-
- Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
-
- if (value == null) {
-
- throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
-
- }
-
- container.addAttribute(name, value);
-
- }
-
- }
-
- }
从initModel方法的代码中可以看出,initModel方法一共做了三件事件。
类图

从类图中可以看出,ServletInvocableHandlerMethod类继承了InvocableHandlerMethod类,而InvocableHandlerMethod类又继承了HandlerMethod这个父类。
HandlerMethod
HandlerMethod类主要是封装了处理程序方法的信息,并提供了对方法参数、方法返回值、方法注释等信息的访问。
HandlerMethod类中的属性
| 名称 | 类型 | 描述 |
| bean | Object | Web控制器方法所在的Web控制器 bean。可以是字符串,代表 bean 的名称; 也可以是 bean 实例对象本身。 |
| beanType | Class | Web控制器方法所在的Web控制器bean 的类型, 如果该bean被代理,这里记录的是被代理的用户类信息 |
| method | Method | Web控制器方法 |
| bridgedMethod | Method | 被桥接的Web控制器方法 |
| parameters | MethodParameter[] | Web控制器方法的参数信息: 所在类所在方法,参数,索引,参数类型 |
| responseStatus | HttpStatus | 注解@ResponseStatus的code属性 |
| responseStatusReason | String | 注解@ResponseStatus的reason属性 |
InvocableHandlerMethod
InvocableHandlerMethod类继承了HandlerMethod类,它在父类的基础上增加了三个属性。
InvocableHandlerMethod类提供了一个重要的方法invokeForRequest,该方法主要是使用反射方式对Method进行调用。
其实@InitBinder注解和@ModelAttribute注解的方法,都是封装成了InvocableHandlerMethod类型的实例。调用InvocableHandlerMethod类型实例的invokeForRequest方法,就是对这两个注解下的方法进行了调用。
- @Nullable
-
- public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
- Object... providedArgs) throws Exception {
-
-
-
- Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
-
- if (logger.isTraceEnabled()) {
-
- logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
-
- "' with arguments " + Arrays.toString(args));
-
- }
-
- Object returnValue = doInvoke(args);
-
- if (logger.isTraceEnabled()) {
-
- logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
-
- "] returned [" + returnValue + "]");
-
- }
-
- return returnValue;
-
- }
invokeForRequest方法中主要做了两件事件。1.是通过getMethodArgumentValues方法,准备好了调用方法所需要的参数。2. 在doInvoke方法中,通过桥接方法,使用反射方式对方法进行了调用。
ServletInvocableHandlerMethod
ServletInvocableHandlerMethod类又继承了InvocableHandlerMethod类。它在提供了invokeAndHandle方法。
- 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;
-
- }
-
- }
在代码中可以看到,ServletInvocableHandlerMethod类的invokeAndHandle方法中,先调用了父类的invokeForRequest方法。在此基础上,1.增加了对ResponseStatus状态的设置。2.对返回值进行了处理。
ModelAndView类中包含了Model和View两个重要的属性。ModelAndView主要用于后台与前端页面交互。它可以保存数据,并重定向或转发到指定页面,然后使用数据来渲染页面。
Model是一个ModelMap类型,而ModelMap继承了LinkedHashMap的这个子类。Model 对象负责在控制器(Controller)和视图(View)之间传递数据。Model属性中的数据会复制到 Servlet Response的属性中。Model相当于一个JOPO的对象。
View是Spring MVC中的视图。视图的作用是渲染数据,将模型model中的数据展示给用户。视图可以用于重定向或转发到指定页面。
HttpRequestHandlerAdapter是专门的http请求处理器的适配器。这里的http请求处理器Handler,是一个实现了org.springframework.web. HttpRequestHandler接口的实例。
我们自定义的http请求处理器,需要实现HttpRequestHandler接口的handleRequest方法。在这个方法实现自己业务逻辑。
handleRequest方法的中提供了HttpServletRequest和HttpServletResponse的两个参数,来供我们使用。
SimpleControllerHandlerAdapter是控制器Controller处理器的适配器。这里的控制器处理器的Handler,是一个实现了org.springframework.web.servlet.mvc.Controller接口的实例。
Spring MVC中提供了org.springframework.web.servlet.mvc.AbstractController的这个抽象类,AbstractController抽象类实现了Controller接口。
在AbstractController中实现Controller接口的handleRequest方法,并提供了handleRequestInternal的这个模板方法留给子类自行扩展。
我们一般会直接继承AbstractController抽象类,并重写handleRequestInternal方法。在handleRequestInternal方法中,我们需要构造一个ModelAndView对象返回即可。