网上介绍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. 转:APP测试总结

  2. C#趣味程序----分数之和

    问题:求这种四个自然数p,q,r,s(p<=q<=r<=s).使得等式1/p + 1/q +1/r +1/s=1成立. 分析:将原式同分,化简整理后得到:2<=p<5,p ...

  3. sql系列(基础篇)-前言 课前补充知识

    前言 课前补充知识 Number(p,s) Number(p,s):数字类型,p 表示数字的有效长度(从数字的左边第 1 位不为 0 的開始算起,直到最右边的长度.取值范围 0~38 位),s 表示数 ...

  4. c++11 实现半同步半异步线程池

    感受: 随着深入学习,现代c++给我带来越来越多的惊喜- c++真的变强大了. 半同步半异步线程池: 事实上非常好理解.分为三层 同步层:通过IO复用或者其它多线程多进程等不断的将待处理事件加入到队列 ...

  5. Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

    安卓出现如下错误,需要增加FLAG_ACTIVITY_NEW_TASK标志 Intent intent1 = new Intent(getApplicationContext(), CameraAct ...

  6. Netty简单介绍(非原创)

    文章大纲 一.Netty基础介绍二.Netty代码实战三.项目源码下载四.参考文章   一.Netty基础介绍 1. 简介 官方定义为:”Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地 ...

  7. JWT和Spring Security集成

    通常情况下,把API直接暴露出去是风险很大的, 我们一般需要对API划分出一定的权限级别,然后做一个用户的鉴权,依据鉴权结果给予用户对应的API (一)JWT是什么,为什么要使用它? 互联网服务离不开 ...

  8. BZOJ 3992 DP+NTT+快速幂

    思路: 普通的DP很好想吧 f[i][j]+=f[i-1][j*s[k]]  前i个数  mod m=j 的个数 m是质数  模数是质数  这就很有趣了 那么我们就求出来原根  所有的数都取指数 搞出 ...

  9. JavaScript——视频插入

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. hdu2647 Reward 拓扑排序

    此题的关键在于分层次,最低一层的人的奖金是888,第二层是888+1 …… 分层可以这样实现.建立反向图.在拓扑排序的时候,第一批入度为0的点就处于第一层,第二批处于第二层 …… 由于是逐个遍历入度为 ...