SpringMVC的处理器适配器-HandlerAdapter的用法及说明
SpringMVC处理器适配器HandlerAdapter用法
如题:
今天看spring源码解析这本书时,看到了这个地方,对于不同HandlerAdapter的使用场景有的困惑,主要还是没见过,因为大多数面向的Controller类型的HandlerAdapter;
HandlerAdapter目前最常见的主要为
1、SimpleControllerHandlerAdapter、HttpRequestHandlerAdapter 、AnnotationMethodHandlerAdapter (已过时),这三个是默认的;如果没有指明新的适配器时,会从这三个中间选择;
2、SimpleServletHandlerAdapter目前很少用到,也不是默认的适配器;
3、RequestMappingHandlerAdapter这个应该是目前springMVC主要采用的,针对方法级的映射匹配处理。
由HandlerAdapter的实现类可知:映射匹配的处理器handler包括三个类型Controller、HttpRequestHandler、Servlet,但后两个的应用场景与使用方式我却没有见到过,经过一番查找,特做一个总结以供以后参考:
1、SimpleControllerHandlerAdapter主要是针对实现Controller接口的handler进行适配,配置方式在书中可见;
2、SimpleServletHandlerAdapter主要是针对实现Servlet接口的handler进行适配,配置方式跟普通的Controller类似,如下所示:
spring配置文件中bean的配置如下:
/** 采用BeanNameUrlHandlerMapping类进行路径映射匹配**/ <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean name="/demo.do" class="com.demo.DemoServlet"/>
对应的Bean实现类为
public class DemoServlet extends HttpServlet{ ....... }
3、HttpRequestHandlerAdapter 主要是针对实现HttpRequestHandler接口的handler进行适配;
HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。它主要应用在基于HTTP的远程调用的实现上。
配置应该与上述相同,从SpringMvc自带的实现类来说,主要用于转发或者静态资源的加载,对应的实现类为DefaultServletHttpRequestHandler和ResourceHttpRequestHandler
浅谈HandlerAdapter
HandlerAdapter顾名思义就是一个适配器,(肯定也采用了适配器模式这里不做过多的解释),那么它的主要作用是什么呢?
HandlerMapping存储了所有都请求映射,请求过来找到相应的请求映射后,返回给我们一个Handler
看这里的代码:
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { Iterator var2 = this.handlerMappings.iterator(); while(var2.hasNext()) { HandlerMapping mapping = (HandlerMapping)var2.next(); HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
这里是DispacherServlet的核心控制方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Object dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
我们拿到Handler之后呢?
接着代码往下走我们可以看到这样一行代码
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
这一步就是讲我们的Handler进行一个HandlerAdapter的适配解析,我们继续代码跟进
public interface HandlerAdapter { //如果当前支持当前handler就执行handler方法 boolean supports(Object handler); @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** @deprecated */ @Deprecated long getLastModified(HttpServletRequest request, Object handler); }
我们知道它采用的适配器模式
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { Iterator var2 = this.handlerAdapters.iterator(); while(var2.hasNext()) { HandlerAdapter adapter = (HandlerAdapter)var2.next(); 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"); }
DispacherServlet中这个方法,就是一个迭代器,给handler找一个适配器,那这一步到底是要做什么呢?
在HandlerAdapter中有四个实现类,分别处理不同Handler我们看一下我们最常用的HttpRequestHandlerAdapter
public boolean supports(Object handler) { return handler instanceof HttpRequestHandler; }
里面就是去判断了,当前handler是不是HttpRequestHandler类型,其实在我们确认号类型的时候,handler经过RequestMappingHandlerMapping,返回的就已经是这个类型的了。
找到适配器之后啊,就是开始参数解析了
String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } }
核心在这里,利用的HandlerAdapter,也就是刚才找到的适配器,和目标方法传进去,执行目标方法。
执行完上面代码,就是判断了一下是不是get请求,HEAD这个不是由我们 去处理的。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
上面这行代码去执行的目标方法。
到这里基本是完成了HandlerAdapter的一个准备工作,找到适配的HandlerAdapter之后,还要进行相应的参数解析啊。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Eclipse+Java+Swing实现图书管理系统(详细代码)
这篇文章主要介绍了Eclipse+Java+Swing实现图书管理系统并附上详细代码,需要的小伙伴可以参考一下,希望对你有所帮助2022-01-01Java多线程工具CompletableFuture的使用教程
CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调、流式处理、多个Future组合处理的能力。本文就来详细讲讲CompletableFuture的使用方式,需要的可以参考一下2022-08-08springmvc HttpServletRequest 如何获取c:forEach的值
这篇文章主要介绍了springmvc HttpServletRequest 如何获取c:forEach的值方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-08-08
最新评论