SpringMVC核心组件HandlerMapping你清楚了吗?
环境:Springboot2.4.11概述
当一个请求过来后Spring是如何进行处理的?下面简单的罗列下请个的过程中核心组件
SpringMVC处理的流程:DispatcherServlet 所有请求的入口HandlerMapping 将请求地址与处理程序关联HandlerAdapter 真正的处理程序,如执行上一步中对应的处理程序HandlerMethodArgumentResolver 对参数进行解析,这里面还涉及到很多其它东西HanlderMethodReturnValueHandler 对返回值进行输出处理ViewResolver 当上一步返回结果为ModelAndView时会应用视图解析器
一个请求的处理过程获取HandlerMapping
该步从容器中获取所有的HandlerMapping对象。public class DispatcherServlet extends FrameworkServlet { private List handlerMappings; private void initHandlerMappings(ApplicationContext context) { // 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。 Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerMappings); } } }查找HandlerMapping
该步从获取的HandlerMapping中查找适合当前请求的HandlerMapping。public class DispatcherServlet extends FrameworkServlet { private List handlerMappings; protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain mappedHandler = null; // 查找能够处理当前请求HandlerMapping对象,主要就是根据请求的URI mappedHandler = getHandler(processedRequest); } protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // HandlerMapping 实现了Ordered接口,是由顺序的,那在这里,谁先匹配谁就处理 for (HandlerMapping mapping : this.handlerMappings) { // 在这个过程中会通过查找到的HandlerMapping对象,然后获取合适的处理程序(可能是个Bean对象或是HandlerMethod对象等) HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; } }
系统默认有如下5个HandlerMappingRequestMappingHandlerMappingBeanNameUrlHandlerMappingRouterFunctionMappingSimpleUrlHandlerMappingWelcomePageHandlerMapping
一般默认都是RequestMappingHandlerMapping匹配
接下来看看是如何进行匹配的
调用父类AbstractHandlerMapping#getHandler方法,父类中的这个方法中定义了特定的逻辑,而针对每种不同的HandlerMapping实现是需要具体的子类来实现AbstractHandlerMapping#getHandlerInternal方法public abstract class AbstractHandlerMapping { public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); // ... HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); // ... return executionChain; } } public abstract class AbstractHandlerMethodMapping { protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 获取请求地址 String lookupPath = initLookupPath(request); try { // 根据请求地址查询对应的HandlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } // ... } protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List matches = new ArrayList<>(); // 在已注册的Mapping中根据请求的url进行查找 // 这样查找的this.pathLookup.get(urlPath); List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); if (!matches.isEmpty()) { Match bestMatch = matches.get(0); // ... handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.getHandlerMethod(); } // ... } }
到这里就是查找处理请求的HandlerMethod对象。接下来看看系统是如何进行初始化所有的HandlerMethod初始化HandlerMethodpublic class RequestMappingHandlerMapping { public void afterPropertiesSet() { // ... super.afterPropertiesSet(); } } public abstract class AbstractHandlerMethodMapping { public void afterPropertiesSet() { initHandlerMethods(); } protected void initHandlerMethods() { // getCandidateBeanNames获取容器中的所有Bean for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { // 根据BeanName获取对应的Class beanType = obtainApplicationContext().getType(beanName); } // ... // isHandler方法判断当前的类是否符合条件,该方法在RequestMappingHandlerMapping中实现 // isHandler方法用处就是判断当前的Class@Controller或者@RequestMapping注解 // 这样就将所有的@Controller与RequestMappingHandlerMapping关联一起了。 if (beanType != null && isHandler(beanType)) { // 查找所有的HandlerMethod detectHandlerMethods(beanName); } } protected void detectHandlerMethods(Object handler) { Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { Class<?> userType = ClassUtils.getUserClass(handlerType); // 查找Class中的所有方法 Map methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup) method -> { try { // 将每一个符合条件的方法(方法上有@RequestMapping注解的) // 封装到RequestMappingInfo对象中 return getMappingForMethod(method, userType); } // ... }); methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); // 将找到的所有Method进行注册添加到Map中 registerHandlerMethod(handler, invocableMethod, mapping); }); } } protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } class MappingRegistry { // T : RequestMappingInfo, handler: 字符串(usersController)Bean名称,method:请求方法对象 public void register(T mapping, Object handler, Method method) { // 创建HandlerMethod对象 HandlerMethod handlerMethod = createHandlerMethod(handler, method); // ... for (String path : directPaths) { // 缓存上,在请求到来的时候 会从这个pathLookup集合中查找 this.pathLookup.add(path, mapping); } } } }
完毕!!!
求个关注+转发
公众:Springboot实战案例锦集
spring data jpa 高级应用
Spring MVC 异常处理方式
Spring事务实现原理源码分析
Spring 自定义Advisor以编程的方式实现AOP
SpringBoot项目中应用Spring Batch批处理框架,处理大数据新方案
Spring IOC容器对Bean实例化的过程详解源码分析
Spring Boot Security防重登录及在线总数
Spring Security记住我功能实现及源码分析
Spring Security 自定义登录成功后的逻辑
承认吧!元气森林的广撒网娱乐营销就是人傻钱多品牌观察02作者小藕编辑阿笔新消费赛道中,跑在最前面的几个,永远是最早抓住细分品类机会的那几个。以在饱受争议中逐渐被人们习惯的0糖气泡水为例元气森林的崛起,走的并非饮料行业常规操作。2016年
接盘辱华品牌的艺人都有谁?杨幂刘雯解约,他们转眼就接手大家还记得前段时间的国外品牌HM耐克等牌子抵制新疆棉花导致一众国内明星与其解约。事情也是过去了一段时间了,风平浪静以后,就有人开始钻空子了。当初解约的明星付了很多违约金,一转眼就有
华为绝不妥协!Mate50系列被多方确认,麒麟芯片5G一个都不少在国内手机市场,iPhone13系列之所以力压群雄销量火热,许多分析人士认为,根本原因就是缺少华为的制衡。当智能手机进入5G时代,华为凭借着前期大量的投入和自身在5G领域半导体领域
电视剧仙剑奇侠传4要来了仙剑奇侠传4电视剧仙剑4终于有消息了,已筹备有4年之久的仙剑4预计在2022年2月开机。仙剑4其实在2016年的时候就已经正式的备案了,但是四年多的时间并没有正式开机的消息传出,直
加密兔正式下线!小米不干了中国基金报记者忆山近日,运营了近四年的小米区块链游戏加密兔宣布即将正式下线。2021年NFT元宇宙概念曾一度爆火,在国内也带火了不少游戏概念公司,而在国外备受追捧的区块链游戏,在国
寻宝埃及埃及艳后的珠宝花园今天我们带着大家来到非洲人口第二大国,可能大家看标题也猜到了吧,今天的主角就是世界四大文明古国金字塔的故乡埃及!埃及金字塔埃及,国土略呈不规则的四方形,地处欧亚非之洲的交通要冲,北
运用到极致的搭配手法渐变与对比FromAltuzarra本场秀运用了轻快明亮的艳色调搭配轻浅色系作为辅邻近色的黄与橙对比色的蓝与黄深浅不同的红色与晴空蓝的撞色,色彩上整体活泼趣味搭配上常用的手法是西装衬衫背心西
NASA发现一颗小行星,估值高达50亿美元,将于2060年实施开采?地球茫茫宇宙中,只是一粒沙子,而人类自己,也许只是沙子上的细菌但放眼宇宙,比地球小的天体还比比皆是,比如月球,比如火星,再比如那些数量未知,经常给地球带来威胁的小行星们。据科学界统
我们根据全世界点击榜单,总结了2021年最热门的主机类游戏文晓生讲个鬼故事,2021年只剩下17天了。年初做的计划完成了吗?立的flag拔掉了吗?许的愿望实现了吗?幼稚,这年头谁还认真做计划啊,新冠变种最后的形态都还没进化出来,能好好活着
神秘的香巴拉,只有拥有纯净心的人才能进入走进香巴拉视频链接httpswww。ixigua。com7024830634740843022?logTag099da744702076f69f73雪域高原上,在美丽的吉雪卧塘,人
拳皇97那些非主流高手玩家们相信广大拳皇97拳迷应该注意到无论高手或或是刚入坑的小白,对战主力基本都是那几个强势角色八神神乐大猪玛丽草薙大门之流,这些强势人物角色对战比赛看久了免不了有审美疲劳之感。大蛇c位妥