SpringMVC源码剖析2——处理器映射器
1.处理器映射器 HandlerMapping
一句话概括作用: 为 我 们 建 立 起 @RequestMapping 注 解 和 控 制 器 方 法 的 对 应 关 系 。
怎么去查看
第一步:
处理器映射器的实体类:
RequestMappingHandlerMapping
父类
RequestMappingInfoHandlerMapping
父类的父类
AbstractHandlerMethodMapping
父类的父类的父类
AbstractHandlerMapping
第二步:找到对应的方法,获取拦截的方法
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public Map<T, HandlerMethod> getHandlerMethods() { this .mappingRegistry.acquireReadLock(); try { return Collections.unmodifiableMap( this .mappingRegistry.getMappings()); } finally { this .mappingRegistry.releaseReadLock(); } } getMappings()代码内容 public Map<T, HandlerMethod> getMappings() { return this .mappingLookup; } |
<ignore_js_op>
此处能看到一个无界HashMap,存储的是映射关系
那么什么时候存进去的呢?
在AbstractHandlerMethodMapping类中有如下代码:
扫描ApplicationContext中的bean,检测并注册处理程序方法。用来扫描bean的
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug( "Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = ( this .detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object. class ) : obtainApplicationContext().getBeanNamesForType(Object. class )); for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null ; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug( "Could not resolve target class for bean with name '" + beanName + "'" , ex); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } } handlerMethodsInitialized(getHandlerMethods()); } |
上述方法将扫描到的Colltroler类当做参数传递到下面的方法,通过反射获取.class字节码,然后再通过反射将方法和方法上面的路径找到存到map中
detectHandlerMethods(beanName);
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
protected void detectHandlerMethods( final Object handler) { Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null ) { final Class<?> userType = ClassUtils.getUserClass(handlerType); Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException( "Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); if (logger.isDebugEnabled()) { logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); } for (Map.Entry<Method, T> entry : methods.entrySet()) { Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); T mapping = entry.getValue(); registerHandlerMethod(handler, invocableMethod, mapping); } } } |
registerHandlerMethod(handler, invocableMethod, mapping);
注册处理程序方法及其唯一映射。在启动时调用
1
2
3
|
protected void registerHandlerMethod(Object handler, Method method, T mapping) { this .mappingRegistry.register(mapping, handler, method); } |
先加锁,后将方法和映射放入Map中的
register(mapping, handler, method);
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public void register(T mapping, Object handler, Method method) { this .readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); assertUniqueMethodMapping(handlerMethod, mapping); if (logger.isInfoEnabled()) { logger.info( "Mapped \"" + mapping + "\" onto " + handlerMethod); } this .mappingLookup.put(mapping, handlerMethod); List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { this .urlLookup.add(url, mapping); } String name = null ; if (getNamingStrategy() != null ) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } |
SpringMVC源码剖析2——处理器映射器的更多相关文章
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段.在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过serv ...
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
上一篇文章<SpringMVC源码剖析(一)- 从抽象和接口说起>中,我介绍了一次典型的SpringMVC请求处理过程中,相继粉墨登场的各种核心类和接口.我刻意忽略了源码中的处理细节,只列 ...
- springMVC源码解析--ViewResolver视图解析器执行(三)
之前两篇博客springMVC源码分析--ViewResolver视图解析器(一)和springMVC源码解析--ViewResolverComposite视图解析器集合(二)中我们已经简单介绍了一些 ...
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
上一篇博客springMVC源码分析--ViewResolver视图解析器(一)中我们介绍了一些springMVC提供的很多视图解析器ViewResolver,在开发的一套springMVC系统中是可 ...
- springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)
之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...
- springMVC源码解析--HandlerMethodArgumentResolverComposite参数解析器集合(二)
上一篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)中我们已经介绍了参数解析相关的东西,并且也提到了HandlerMethodArgume ...
- SpringMVC源码剖析1——执行流程
SpringMVC源码剖析1——执行流程 00.SpringMVC执行流程file:///C:/Users/WANGGA~1/AppData/Local/Temp/enhtmlclip/Image.p ...
- 《SpringMVC从入门到放肆》四、SpringMVC配置式开发(处理器映射器)
上一篇我们讲解了DispatcherServlet的url-pattern配置详解,今天我们来真正对SpringMVC进行配置式开发.所谓配置式开发是指“处理器类是程序员自己定义的.实现了特定接口的类 ...
- SpringMVC源码情操陶冶-InterceptorsBeanDefinitionParser拦截器解析器
解析mvc:interceptors节点 观察下InterceptorsBeanDefinitionParser的源码备注 /** * {@link org.springframework.beans ...
随机推荐
- Ctrl +c 脚本中
#!/bin/bashsar -n DEV 1 111111111111111 >>1.txt & #实时网卡流量数据 sleep 3 && kill -2 ...
- shell的一些一句话东西
shell的一些一句话东西 2010-09-10 11:22:58| 分类: linux shell | 标签:shell linux |举报|字号 订阅 time -p [程序] 可 ...
- sklearn 模型评估
原文链接 http://d0evi1.com/sklearn/model_evaluation/ 预测值:pred 真实值:y_test #### 直接用平均值 ``` mean(pred == y_ ...
- Java目录下文件夹的含义和运行机制
Java安装目录下的各个文件夹的意义 >bin 放置Java所有的可执行文件 >include 一些C语言的头文件 >jre Java的运行环境 >lib Java的类库文件 ...
- php 随机useragent
<?php /** * 获取随机useragent */ private function get_rand_useragent($param) { $arr = array( 'Mozilla ...
- python语法基础-并发编程-进程-进程池以及回调函数
############### 进程池 ############## """ 进程池的概念 为什么会有进程池? 1,因为每次开启一个进程,都需要创建一个内存空间 ...
- js中call和apply的实现原理
js中call和apply的实现原理 实现call的思路: /* 还有就是call方法是放在Function().prototype上的也就是构造函数才有的call方法 (我门可 ...
- java截取字符串并拼接
一.substirng public static void main(String[] args) { String sendContent = "请查收:www.baidu.com&qu ...
- eclipse Java EE 与 Java 区别
1. 综述 eclipse IDE 一般来说有三种可切换的模式 Java EE Java 调试 可直接下拉至底部看两者的比较. 2. Java Java 是带有用户界面的 基本IDE ,缺少数据库和w ...
- 面向对象 part5
构造函数模式与原型模式结合 function Person(name) = { this.name = name this.friends = ["a", "b" ...