SpringMVC中的HandlerAdapter
来源:互联网 发布:开源软件二次开发 编辑:程序博客网 时间:2024/06/06 02:02
SpringMVC中的HandlerAdapter
还记得在DispatcherServlet中SpringMVC处理请求的逻辑吗,网上有一个非常棒的图,阐明了请求分发处理的整个过程。
映射处理器HandlerMapping根据Request返回一个HandlerExecutionChain实例,HandlerExecutionChain并不是真正的处理器Handler,而是包含了Handler以及拦截器HandlerInterceptor的封装后的调用链对象。系统中可能存在多个HandlerMapping,不同的HandlerMapping对应着不同的策略。DispatcherServlet根据先后顺序,哪个HandlerMapping最先找到处理器,则使用当前的处理器并且立即停止继续查找。
DispatcherServlet获取到处理器Handler后,它并不知道如何使用这个处理器。因为处理器可能多种多样,没有遵循一种标准,它只是一个Object。所以这里需要多Handler进行适配,使得所有的处理器共同拥有一个标准的接口处理请求。Spring使用的适配器的名字就是HandlerAdapter,看它的定义:
public interface HandlerAdapter {boolean supports(Object handler); ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;long getLastModified(HttpServletRequest request, Object handler);}supports方法用来判断是否支持当前的处理器,handler方法用来处理请求返回ModelAndView。选取HandlerAdapter的方式跟HandlerMapping的方式非常相似,只不过一个是根据请求选取处理器,一个是根据处理器选取处理器的适配器。下面是选取HandlerAdapter的方法
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 +"]: Does your handler implement a supported interface like Controller?");}可以看出,HandlerAdapter需要与HandlerMapping配合使用,如果HandlerMapping返回的处理器没有对应的适配器是会出现异常的。
HandlerAdapter的初始化
和HandlerMapping一样,HandlerAdapter的初始化也在DispatcherServlet的initStrategies方法中,具体初始化方法如下:
private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;if (this.detectAllHandlerAdapters) {// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());// We keep HandlerAdapters in sorted order.OrderComparator.sort(this.handlerAdapters);}}else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");}}}首先尝试向容器索取HandlerAdapter,索要的方式分为两种:第一种是根据类型获取所有的HandlerAdapter类型的Bean,另一种是根据名字向容器索要名字为“handlerAdapter”的Bean。具体使用哪种方式根据参数detectAllHandlerAdapters决定,默认为true,可以在web.xml中设置。
若容器中没有找到HandlerAdapter,则spring会加载使用默认的HandlerAdapter。其实不仅HandlerAdapter是这样,DispatcherServlet的一些其它组件在某些情况也会使用默认的配置。它们通过一个共同的方法获取:
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {String key = strategyInterface.getName();String value = defaultStrategies.getProperty(key);if (value != null) {String[] classNames = StringUtils.commaDelimitedListToStringArray(value);List<T> strategies = new ArrayList<T>(classNames.length);for (String className : classNames) {try {Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());Object strategy = createDefaultStrategy(context, clazz);strategies.add((T) strategy);}catch (ClassNotFoundException ex) {throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]", ex);}catch (LinkageError err) {throw new BeanInitializationException("Error loading DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]: problem with class file or dependent class", err);}}return strategies;}else {return new LinkedList<T>();}}
这个defaultStrategies加载自配置文件,加载过程如下
private static final Properties defaultStrategies;static {// Load default strategy implementations from properties file.// This is currently strictly internal and not meant to be customized// by application developers.try {ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);}catch (IOException ex) {throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());}}
找到对应位置的配置文件,并且找到关于HandlerAdapter的配置
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
如上所示,容器中HandlerAdapter的时候就会使用配置好的上面的三种HandlerAdapter。如果在spring的配置文件中加入 <mvc:annotation-driven />,则它的实现类AnnotationDrivenBeanDefinitionParser会自动向容器注册RequestMappingHandlerAdapter和RequestMappingHandlerMapping。
- SpringMVC中的HandlerAdapter
- springMVC--HandlerAdapter
- springMVC (三) HandlerAdapter
- SpringMVC handlerMapping和handlerAdapter
- SpringMVC之HandlerAdapter解析
- SpringMVC之HandlerAdapter解析
- SpringMVC-HandlerAdapter简介
- SpringMVC 流程(3)-- HandlerAdapter
- SpringMVC源码解析- HandlerAdapter初始化
- 11.SpringMVC 请求处理 - HandlerAdapter
- SpringMVC之HandlerMapping和HandlerAdapter
- SpringMVC之 HandlerAdapter和handlerMapping
- SpringMVC学习(三)--handlerMapping和handlerAdapter
- springmvc Handler HandlerMapping HandlerAdapter的配置方式
- SpringMVC源码分析 之 HandlerMapping和HandlerAdapter
- 第四章 SpringMVC之HandlerAdapter解析
- SpringMVC源码 HandlerMapping和HandlerAdapter(1)
- SpringMVC源码 HandlerMapping和HandlerAdapter(2)
- 海量数据处理
- mysql 5.7.9 安装问题
- 面试题15、输入一个链表,输出该链表中倒数第k个结点。
- IP和mac地址映射关系(想找好久了)
- npm 更换国内源
- SpringMVC中的HandlerAdapter
- wordpress 图片裁剪问题处理
- HDU (杭电) 计算机学院大学生程序设计竞赛(2015’11)
- 《leetCode》:Valid Number
- 轻松实现 自定义slidingMenu+viewPager+scrollView
- 2015年9-10
- Microsoft Word 插件开发——Word外接应用程序开发
- 用第三方框架GDataXMLNode解析XML数据:
- CodeForces 120F|Spiders|树形DP|求树最长链