通俗易懂聊springMVC中的handler是什么
1.handler是什么
2. handler是如何获取的(不关注分析过程可以跳过直接看总结
3.handle简单总结
1.handler是什么
了解过SpingMVC流程的同学一定听说过handler,百度翻译过来是处理者,很多博客中称之为处理器.那就按照大部分人的说法称呼它为控制器.说到控制器,会不会联想到我们平常写业务代码中的各种controller,也是控制器,是不是一种东西啊,这里可以大胆猜测一下就是一种东西嘛.好,现在通过源码进行验证猜测!
如果直接从源码中按照类文件类型直接搜索Handler是找不到的,根据springMVC的工作流程开始捋(有很多帖子说过这里不在重述),最早出现handler是在这个地方:
AbstractHandlerMapping.java中getHandler()
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// 获取handler,如果获取为空则使用默认handler,如果默认的也没有则返回nullObject handler = getHandlerInternal(request);// 省略部分代码....}
测试案例发送实际请求:
@RequestMapping("/test")
@RestController
public class Test {@GetMapping("/add")public String add(String a,Personal personal,@RequestParam(name = "genderType") int gender){int i=0;return a;}}
对应请求来看一下debugg
Object handler = getHandlerInternal(request);
中handler具体是什么内容,截图如下
从中可以看到handler实际上一个HandlerMethod类型对象,里面的属性有请求所在的类信息、请求方法、请求参数等内容。所以从这里可以认为handler相当于是平常业务代码中每个请求对应的的controller类以及方法信息.上面debug截图对应起来更容易理解!
2.handler是如何获取的
项目启动过程中会有包扫描,与本贴相关的扫描内容是将类上标注@RequestMapping的类信息以及方法上带有@RequestMapping的方法信息扫描到容器中(注意符合restful风格的@GetMapping、@PostMapping等标注的方法信息也会扫描进去,下文会有介绍).每个带有以上注解的方法扫描到容器中都会有一个RequestMappingInfo(请求映射信息,实际上就是注解中各项属性和属性值的数据组装信息)。
具体请求过程实际上是从Map<RequestMappingInfo, MappingRegistration<RequestMappingInfo>>
中根据请求对应的RequestMappingInfo获取对应的MappingRegistration,其中含有handler(实际上是HandlerMethod)。
先说项目启动,扫描@RequestMapping处理核心处理
RequestMappingHandlerMapping.java中getMappingForMethod()
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {// 根据方法上标注@RequestMapping注解获取RequestMappingInfoRequestMappingInfo info = createRequestMappingInfo(method);if (info != null) {// 根据方法所在类上标注@RequestMapping注解获取RequestMappingInfoRequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);if (typeInfo != null) {// 将按照类获取的RequestMappingInfo 与方法获取的RequestMappingInfo 进行组装生成新方法级别上的RequestMappingInfoinfo = typeInfo.combine(info);}// 省略部分代码....}return info;}
根据类信息或是方法信息创建RequestMapping的处理:
RequestMappingHandlerMapping.java中createRequestMappingInfo()
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
// 获取类或是方法上带有@RequestMapping注解的RequestMapping注解信息(@GetMaping、@PostMapping等都是按照@RequestMapping进行解析,此类注解只不过是指定method为对应的GTE或POST请求方式的@RequestMapping)RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);// 获取类或是方法上自定义请求条件,此处都返回nullRequestCondition<?> condition = (element instanceof Class ?getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);}
具体组装RequestMappingInfo 逻辑:
RequestMappingHandlerMapping.java中createRequestMappingInfo()的重载方法
protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {// 此处是读取@RequestMapping注解中各种属性值.比如说请求路径信息path、请求头信息headers、请求方式信息method等信息。RequestMappingInfo.Builder builder = RequestMappingInfo.paths(resolveEmbeddedValuesInPatterns(requestMapping.path())).methods(requestMapping.method()).params(requestMapping.params()).headers(requestMapping.headers()).consumes(requestMapping.consumes()).produces(requestMapping.produces()).mappingName(requestMapping.name());if (customCondition != null) {builder.customCondition(customCondition);}return builder.options(this.config).build();}
至此项目启动,能扫描到的类中所有带有@RequestMapping注解的方法都有一个RequestMappingInfo创建加载完成。
发送请求获取HandlerMethod 逻辑
AbstractHandlerMethodMapping.java中getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {// 获取请求路径,此处不做展开介绍String lookupPath = initLookupPath(request);// 省略部分代码try {// 根据请求路径以及请求信息获取HandlerMethodHandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);}// 省略部分代码}
获取的具体逻辑在
AbstractHandlerMethodMapping.java中lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {List<Match> matches = new ArrayList<>();List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);if (directPathMatches != null) {addMatchingMappings(directPathMatches, matches, request);}if (matches.isEmpty()) {addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);}if (!matches.isEmpty()) {Match bestMatch = matches.get(0);// 省略部分代码bestMatch.getHandlerMethod());handleMatch(bestMatch.mapping, lookupPath, request);return bestMatch.getHandlerMethod();}// 省略部分代码}
梳理一下上面的逻辑:HandlerMethod由bestMatch.getHandlerMethod()
获取,bestMatch由matches.get(0)
获取,matches是由addMatchingMappings(directPathMatches, matches, request);
进行封装处理而来.下面就继续看addMatchingMappings方法.
AbstractHandlerMethodMapping.java中addMatchingMappings()
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {for (T mapping : mappings) {T match = getMatchingMapping(mapping, request);if (match != null) {matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));}}}
从上面可以发现matches中由Match组装而来,查看Match实现发现HandlerMethod是由getHandlerMethod()而来(见Match实现).到这终于搞清楚HandlerMethod的最终出处.
private class Match {private final T mapping;private final MappingRegistration<T> registration;public Match(T mapping, MappingRegistration<T> registration) {this.mapping = mapping;this.registration = registration;}public HandlerMethod getHandlerMethod() {return this.registration.getHandlerMethod();}// 省略部分代码.....}
那问题来了,映射注册器中MappingRegistration中如何进行组装的HandlerMethod.不要着急请继续往下看.
分析发现项目启动过程中,容器会将所有’‘认为’'是handler的bean(实际就是带有@Controller或是@RequestMapping的类,至于为什么下面有讲)中的方法对象method与映射对象信息RequestMapping进行做注册匹配.
RequestMappingHandlerMapping.java中isHandler
protected boolean isHandler(Class<?> beanType) {//定义了哪种beanType符合Handler.即类中有@Controller或是@RequestMapping注解return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));}
注册匹配具体处理:
将handler与对应的requestMapping做对应匹配放到注册器中.
public void register(T mapping, Object handler, Method method) {// 省略部分代码....// 按照handler与method对象进行组装HandlerMethod.(两个参数对应测试案例中的类的beanName:test,以及请求方法对象:public java.lang.String com.it.txm.demo.methodReslove.Test.add(java.lang.String,com.it.txm.demo.methodReslove.Personal,int));创建过程就是简单的构造函数创建,不深入分析.HandlerMethod handlerMethod = createHandlerMethod(handler, method);// 省略部分代码....// 将requestMappingInfo和包含handlerMethod的信息组装到映射MappingRegistrythis.registry.put(mapping,new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));}
至此handlerMethod的来龙去脉已经梳理完毕!
3.handler简单总结
handler相当于是平常业务代码中每个请求对应的的controller类以及方法信息.文章第一部分的debug截图对应起来更容易理解!
handler来源分析:
1.项目启动过程中将所带有@RequestMapping注解的方法对应创建一个requestMappingInfo对象(存储注解中各属性信息);
2.项目启动过程中,容器会将所有的认为是handler的bean中的每个方法进行匹配处理,期间会创建handlerMethod,将映射信息RequestMappingInfo与MappingRegistration(其中包含handlerMethod)进行组装map处理,前者为key,后者为value.
3.发送请求,解析请求信息,从Map<RequestMappingInfo, MappingRegistration<RequestMappingInfo>>
中根据RequestMappingInfo获取MappingRegistration信息,在从中获取HandlerMethod.
通俗易懂聊springMVC中的handler是什么相关推荐
- springmvc中的设计模式---适配器模式_晏无心_新浪博客
springmvc的基本流程在之前的文章里都大致分析完了,接下来总结下springmvc中运用了哪些设计模式. 一.设计模式 什么是设计模式,通俗来讲,就是是一套被反复使用.多数人知晓的.经过分类的. ...
- JavaEE开发之SpringMVC中的自定义拦截器及异常处理
上篇博客我们聊了<JavaEE开发之SpringMVC中的路由配置及参数传递详解>,本篇博客我们就聊一下自定义拦截器的实现.以及使用ModelAndView对象将Controller的值加 ...
- SpringMVC中的拦截器
SpringMVC中的拦截器 拦截器的作用 Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理. 用户可以自己定义一些拦截器来实现 ...
- SpringMVC 中的异常处理
SpringMVC 中的异常处理 异常处理的思路 系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发.测试通过手段减 ...
- springMVC中Dispatcher中的/和/*的区别
1. 首先 / 这个是表示默认的路径,及表示:当没有找到可以匹配的URL就用这个URL去匹配. 2. 在springmvc中可以配置多个DispatcherServlet,比如: 配置多个Dispat ...
- 框架:SpringMVC中Interceptor拦截器的两种实现
Spring中使用Interceptor拦截器 SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证, ...
- SpringMVC中使用Interceptor拦截器
2019独角兽企业重金招聘Python工程师标准>>> SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理. ...
- 一篇文章教你弄懂 SpringMvc中的HandlerInterceptor
文章列表 一.HandlerInterceptor简介 一.HandlerInterceptor应用实例 写在前面: 我是「境里婆娑」.我还是从前那个少年,没有一丝丝改变,时间只不过是考验,种在心中信 ...
- java中的model_Java程序员必看之springmvc中的Model对象在重定向中的数据
原标题:Java程序员必看之springmvc中的Model对象在重定向中的数据 在springmvc框架中,一个handler方法中的参数可以内置接收Model类型的对象,主要用于存储数据之用,主要 ...
最新文章
- java订单实现的_java订单系统的开发
- ucache来广营(望京)机房
- “一切都是消息”--iMSF(即时消息服务框架)之【请求-响应】模式(点对点)...
- 嵌套母版页中的控件访问
- JDK版本Java SE、Java EE、Java ME的区别
- C++ vector 使用详解
- xml.query() 实例演示
- app运行租用服务器,app租用服务器
- python 映射网络驱动器_用Delphi实现网络驱动器的映射和断开
- Lockdir 文件夹加密 破解
- 毕业生见习期考核鉴定表(单位考核意见)
- 查看英伟达NVIDIA显卡型号
- linux head
- Jmeter把响应数据结果保存到本地文件
- 怎么更改當前的USERENV(#39;LANG#39;)返回值 oracle
- LaTeX入门学习(2)(安装)
- 毁掉一个孩子只要十步(80%的家长都在做)
- 哈代-温伯格平衡定律(The Hardy-Weinberg Equilibrium)
- 2015计算机考试成绩查询网址,2015年下半年软考成绩查询入口!
- html带复选框的表格,Html 表格行 ID 复选框
热门文章
- Git 工作中怎么用?
- 2021年中式烹调师(中级)考试题及中式烹调师(中级)找解析
- p16panda合并concat
- 盘点美国最出人意料的20种高薪职业
- Java练习:单选题
- ctfshow---命令执行
- 江西省南昌市谷歌高清卫星地图下载(百度网盘离线包下载)
- css旋转不围绕圆心,css3:元素总是围绕中心旋转[关闭](css3: element always rotates around center [closed])...
- 制药实验室信息管理系统(LIMS)
- MySql高级(教学版)