网上介绍HandlerMapping和HandlerAdapter的文章很多,今天我用自己的理解和语言来介绍下HandlerMapping和HandlerAdapter

一. HandlerMapping和HandlerAdapter的作用和背景:

SpringMVC的M、V、C就不说了,HandlerMapping就是用来存放用户Request(具体可以理解为一个请求URL)和处理具体请求的Handler中的method关系的地方,例如:将/query?id=XXX的请求交给XXXService.queryById(int id)这个方法来处理。

真正调用一个方法,首先必须找到方法定义,然后传入实参。HandlerMapping是用来映射URL和method的关系的话,HandlerAdapter是用来负责传递方法的实参。

二. HandlerMapping和HandlerAdapter的构成:

在Spring源码中,HandlerMapping含有HandlerExcutionChain对象,HandlerExcutionChain是由Handler和拦截器组成。有兴趣可以看下源代码,这里我仍然用自己的理解和语言来描述。

HandlerExcutionChain你可以理解为一个对象,它是由Object(实际上就是Controller)、URL Pattern(URL的封装)和Method组成(具体对应的就是HandlerExcutionChain中的handler、interceptors),或者你可以这么理解HandlerMapping就是List<MyHandlerMapping(handler,method,url)>,URL请求交给Controller的method()来处理。

其中handler就是SpringMVC中所有的Controller(例如:加上@Controller的类),可以循环context中所有BeanName对应的Bean,判断Bean对象是否有@Controller标签来实现。method就是Controller中具体执行请求的方法,通过循环Bean中的所有method,判断是否有@RequestMapping的value和请求的url是否匹配。url就是把Controller和method的@RequestMapping拼起来。

HandlerAdapter是用来存放调用Controller的method时传入的形参类型,在SpringMVC中参数都是在请求URL上带入的。我们可以把HandlerAdapter理解为一个Map<HandlerMapping,paramMapping<position index,param type>>,其中HandlerMapping是用来保存请求的URL和Controller的method之间的关系,paramMapping用来保存该HandlerMapping.method的形参类型(paramMapping的key是position index,value是param type)

// HandlerMapping源码
public interface HandlerMapping {
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes"; HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
} // HandlerExcutionChain源码
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex;
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[])null);
} public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
this.interceptorIndex = -1;
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain)handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
} else {
this.handler = handler;
this.interceptors = interceptors;
} } public Object getHandler() {
return this.handler;
} public void addInterceptor(HandlerInterceptor interceptor) {
this.initInterceptorList().add(interceptor);
} public void addInterceptors(HandlerInterceptor... interceptors) {
if (!ObjectUtils.isEmpty(interceptors)) {
CollectionUtils.mergeArrayIntoCollection(interceptors, this.initInterceptorList());
} } private List<HandlerInterceptor> initInterceptorList() {
if (this.interceptorList == null) {
this.interceptorList = new ArrayList();
if (this.interceptors != null) {
CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
}
} this.interceptors = null;
return this.interceptorList;
} public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = (HandlerInterceptor[])this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
} return this.interceptors;
} boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
} return true;
} void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
} } void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i]; try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
} } void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
if (interceptors[i] instanceof AsyncHandlerInterceptor) {
try {
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor)interceptors[i];
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
} catch (Throwable var6) {
logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", var6);
}
}
}
} } public String toString() {
Object handler = this.getHandler();
if (handler == null) {
return "HandlerExecutionChain with no handler";
} else {
StringBuilder sb = new StringBuilder();
sb.append("HandlerExecutionChain with handler [").append(handler).append("]");
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
sb.append(" and ").append(interceptors.length).append(" interceptor");
if (interceptors.length > 1) {
sb.append("s");
}
} return sb.toString();
}
}
}

按照自己理解写的intiHandlerMapping()方法:

private void initHandlerMappings(ApplicationContext context) {
//首先从容器中取到所有的实例
String[] beanNames = context.getBeanDefinitionNames();
try {
for (String beanName : beanNames) {
Object controller = context.getBean(beanName);
Class<?> clazz = controller.getClass();
//但是不是所有的牛奶都叫特仑苏,只有带有@Controller的才处理
if (!clazz.isAnnotationPresent(Controller.class)) {
continue;
} String baseUrl = ""; if (clazz.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
baseUrl = requestMapping.value();
} //扫描所有的public方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(RequestMapping.class)) {
continue;
}
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
String regex = ("/" + baseUrl + requestMapping.value().replaceAll("\\*", ".*")).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(regex);
this.handlerMappings.add(new HandlerMapping(pattern, controller, method));
System.out.println("Mapping: " + regex + " , " + method);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

SpringMVC-HandlerMapping和HandlerAdapter的更多相关文章

  1. SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

    SpringMVC在使用过程中,大多是使用注解,对它的实现接口之类的关系理解变得模糊, 通过对XML配置的理解,可以理清各个类的关系,譬如控制器类要实现Controller接口. 接触SpringMV ...

  2. Spring MVC源码分析(三):SpringMVC的HandlerMapping和HandlerAdapter的体系结构设计与实现

    概述在我的上一篇文章:Spring源码分析(三):DispatcherServlet的设计与实现中提到,DispatcherServlet在接收到客户端请求时,会遍历DispatcherServlet ...

  3. springMVC3学习(三)--handlerMapping和handlerAdapter

    基本结构和 springMVC3学习(一)--框架搭建 差不多,这里不再用Annotation注解的方式 以下只说明需要修改的部分: 1.在Spring配置文件中配置HandlerMapping.Ha ...

  4. HandlerMapping和HandlerAdapter配置须知

    ---------------------siwuxie095                                 HandlerMapping 和 HandlerAdapter 配置须知 ...

  5. 从源码的角度彻底搞懂 HandlerMapping 和 HandlerAdapter

    彻底搞懂 HandlerMapping和HandlerAdapter 知识点的回顾: 当Tomcat接收到请求后会回调Servlet的service方法,一开始入门Servlet时,我们会让自己的Se ...

  6. Spring mvc之源码 handlerMapping和handlerAdapter分析

    Spring mvc之源码 handlerMapping和handlerAdapter分析 本篇并不是具体分析Spring mvc,所以好多细节都是一笔带过,主要是带大家梳理一下整个Spring mv ...

  7. Spring MVC中的HandlerMapping与HandlerAdapter

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  8. [Java] SpringMVC工作原理之二:HandlerMapping和HandlerAdapter

    一.HandlerMapping 作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecu ...

  9. SpringMVC工作原理 : HandlerMapping和HandlerAdapter

    一.HandlerMapping 作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecu ...

  10. Spring MVC 梳理 - handlerMapping和handlerAdapter分析

    参考图片 综上所述我们来猜测一下spring mvc 中根据URL找到处理器Controller中相应方法的流程 ①:获取Request的URL ②:从UrlLookup这个map中找到相应的requ ...

随机推荐

  1. ios设计一部WindowsPhone手机

    ios设计一部WindowsPhone手机 main.m #import <Foundation/Foundation.h> #import "WindowsPhone.h&qu ...

  2. Linux 强行终止

    kill -9 pid pid是进程号 -9 代表的是数字 INT 2 这个就是你在bash下面用Ctrl+C 来结束一个程序时,bash会向进程发送这个信号,默认的,进程收到这个程序会结束. 你可以 ...

  3. 【SDOI 2008】 仪仗队

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2190 [算法] 同POJ3090 值得注意的是此题数据规模较大,建议使用用线性筛筛出 ...

  4. HDU2080 夹角有多大2

    2019-05-17 15:00:09 加油加油,fightting !!! 这道题不知道acos()函数,acos()返回的是弧度,转化成度数要 / PI * 180 也没有想到通过向量 但是想到了 ...

  5. golang图片压缩

    package main import (    //"encoding/json"    "fmt"    //"os"    //&qu ...

  6. POJ 2406 KMP next数组的应用

    题意:让你找最小重复串的个数 加深KMP中对next数组的理解 #include <cstdio> #include <cstring> using namespace std ...

  7. Java图片的压缩

    1.如果在springMvc中,会自带生成MultipartFile文件,将MultipartFile转化为File MultipartFile file1 = file; CommonsMultip ...

  8. Session版购物车+MVC局部刷新

     效果图: 大致代码: <script type="text/javascript"> $(function () { LoadOrderDetailList(); } ...

  9. ABP框架应用汇总

        相信很多人可能听过或没听过ABP这个框架,在我接触此框架时也是在现在所在的公司开始接触的,我们用此开源框架作为我们项目的架构,我们正好做的是Saas云服务多租户管理系统开发,并且经过了一年多高 ...

  10. angular实现动态的留言板案例

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...