RequestMappingHandlerMapping getMappingForMethod

RequestMappingHandlerMapping 继承于 AbstractHandlerMethodMapping 而AbstractHandlerMethodMapping实现了InitializingBean接口,

会调用初始化后的方法afterPropertiesSet(),此方法中主要功能是通过isHandler(beanType)把类及方法中包括Controller RequestMapping注解的所有的类都找出来,

然后循环每个类,找出所有方法相对应的url路径(结合class RequestMapping注解的路径)组合成完整的请求路径,然后注册到MappingRegistry 类的集合中,以便后面使用


  1. /**
  2. * {@inheritDoc}
  3. * <p>Expects a handler to have either a type-level @{@link Controller}
  4. * annotation or a type-level @{@link RequestMapping} annotation.
  5. */
  6. @Override
  7. protected boolean isHandler(Class<?> beanType) {
  8. return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
  9. AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
  10. }
  11. /**
  12. * Uses method and type-level @{@link RequestMapping} annotations to create
  13. * the RequestMappingInfo.
  14. * @return the created RequestMappingInfo, or {@code null} if the method
  15. * does not have a {@code @RequestMapping} annotation.
  16. * @see #getCustomMethodCondition(Method)
  17. * @see #getCustomTypeCondition(Class)
  18. */
  19. @Override
  20. @Nullable
  21. protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
  22. RequestMappingInfo info = createRequestMappingInfo(method);
  23. if (info != null) {
  24. RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
  25. if (typeInfo != null) {
  26. info = typeInfo.combine(info);
  27. }
  28. String prefix = getPathPrefix(handlerType);
  29. if (prefix != null) {
  30. info = RequestMappingInfo.paths(prefix).build().combine(info);
  31. }
  32. }
  33. return info;
  34. }
  35. @Nullable
  36. String getPathPrefix(Class<?> handlerType) {
  37. for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
  38. if (entry.getValue().test(handlerType)) {
  39. String prefix = entry.getKey();
  40. if (this.embeddedValueResolver != null) {
  41. prefix = this.embeddedValueResolver.resolveStringValue(prefix);
  42. }
  43. return prefix;
  44. }
  45. }
  46. return null;
  47. }
  48. /**
  49. * Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},
  50. * supplying the appropriate custom {@link RequestCondition} depending on whether
  51. * the supplied {@code annotatedElement} is a class or method.
  52. * @see #getCustomTypeCondition(Class)
  53. * @see #getCustomMethodCondition(Method)
  54. */
  55. @Nullable
  56. private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
  57. RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
  58. RequestCondition<?> condition = (element instanceof Class ?
  59. getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
  60. return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
  61. }
  62. /**
  63. * Create a {@link RequestMappingInfo} from the supplied
  64. * {@link RequestMapping @RequestMapping} annotation, which is either
  65. * a directly declared annotation, a meta-annotation, or the synthesized
  66. * result of merging annotation attributes within an annotation hierarchy.
  67. */
  68. protected RequestMappingInfo createRequestMappingInfo(
  69. RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
  70. RequestMappingInfo.Builder builder = RequestMappingInfo
  71. .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
  72. .methods(requestMapping.method())
  73. .params(requestMapping.params())
  74. .headers(requestMapping.headers())
  75. .consumes(requestMapping.consumes())
  76. .produces(requestMapping.produces())
  77. .mappingName(requestMapping.name());
  78. if (customCondition != null) {
  79. builder.customCondition(customCondition);
  80. }
  81. return builder.options(this.config).build();
  82. }

AbstractHandlerMethodMapping implements InitializingBean

  1. /**
  2. * Provide the mapping for a handler method. A method for which no
  3. * mapping can be provided is not a handler method.
  4. * @param method the method to provide a mapping for
  5. * @param handlerType the handler type, possibly a sub-type of the method's
  6. * declaring class
  7. * @return the mapping, or {@code null} if the method is not mapped
  8. */
  9. @Nullable
  10. protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
  11. /**
  12. * Detects handler methods at initialization.
  13. * @see #initHandlerMethods
  14. */
  15. @Override
  16. public void afterPropertiesSet() {
  17. initHandlerMethods();
  18. }
  19. /**
  20. * Scan beans in the ApplicationContext, detect and register handler methods.
  21. * @see #getCandidateBeanNames()
  22. * @see #processCandidateBean
  23. * @see #handlerMethodsInitialized
  24. */
  25. protected void initHandlerMethods() {
  26. for (String beanName : getCandidateBeanNames()) {
  27. if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
  28. processCandidateBean(beanName);
  29. }
  30. }
  31. handlerMethodsInitialized(getHandlerMethods());
  32. }
  33. /**
  34. * Invoked after all handler methods have been detected.
  35. * @param handlerMethods a read-only map with handler methods and mappings.
  36. */
  37. protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) {
  38. // Total includes detected mappings + explicit registrations via registerMapping
  39. int total = handlerMethods.size();
  40. if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) {
  41. logger.debug(total + " mappings in " + formatMappingName());
  42. }
  43. }
  44. /**
  45. * Determine the type of the specified candidate bean and call
  46. * {@link #detectHandlerMethods} if identified as a handler type.
  47. * <p>This implementation avoids bean creation through checking
  48. * {@link org.springframework.beans.factory.BeanFactory#getType}
  49. * and calling {@link #detectHandlerMethods} with the bean name.
  50. * @param beanName the name of the candidate bean
  51. * @since 5.1
  52. * @see #isHandler
  53. * @see #detectHandlerMethods
  54. */
  55. protected void processCandidateBean(String beanName) {
  56. Class<?> beanType = null;
  57. try {
  58. beanType = obtainApplicationContext().getType(beanName);
  59. }
  60. catch (Throwable ex) {
  61. // An unresolvable bean type, probably from a lazy bean - let's ignore it.
  62. if (logger.isTraceEnabled()) {
  63. logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
  64. }
  65. }
  66. if (beanType != null && isHandler(beanType)) {
  67. //====================================
  68. detectHandlerMethods(beanName);
  69. }
  70. }
  71. /**
  72. * Look for handler methods in the specified handler bean.
  73. * @param handler either a bean name or an actual handler instance
  74. * @see #getMappingForMethod
  75. */
  76. protected void detectHandlerMethods(Object handler) {
  77. Class<?> handlerType = (handler instanceof String ?
  78. obtainApplicationContext().getType((String) handler) : handler.getClass());
  79. if (handlerType != null) {
  80. Class<?> userType = ClassUtils.getUserClass(handlerType);
  81. Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
  82. (MethodIntrospector.MetadataLookup<T>) method -> {
  83. try {
  84. return getMappingForMethod(method, userType);
  85. }
  86. catch (Throwable ex) {
  87. throw new IllegalStateException("Invalid mapping on handler class [" +
  88. userType.getName() + "]: " + method, ex);
  89. }
  90. });
  91. if (logger.isTraceEnabled()) {
  92. logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
  93. }
  94. methods.forEach((method, mapping) -> {
  95. Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
  96. registerHandlerMethod(handler, invocableMethod, mapping);
  97. });
  98. }
  99. }
  100. /**
  101. * Register a handler method and its unique mapping. Invoked at startup for
  102. * each detected handler method.
  103. * @param handler the bean name of the handler or the handler instance
  104. * @param method the method to register
  105. * @param mapping the mapping conditions associated with the handler method
  106. * @throws IllegalStateException if another method was already registered
  107. * under the same mapping
  108. */
  109. protected void registerHandlerMethod(Object handler, Method method, T mapping) {
  110. this.mappingRegistry.register(mapping, handler, method);
  111. }
  112. /**
  113. * A registry that maintains all mappings to handler methods, exposing methods
  114. * to perform lookups and providing concurrent access.
  115. * <p>Package-private for testing purposes.
  116. */
  117. class MappingRegistry {
  118. private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
  119. private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
  120. private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
  121. private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
  122. private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
  123. private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  124. /**
  125. * Return all mappings and handler methods. Not thread-safe.
  126. * @see #acquireReadLock()
  127. */
  128. public Map<T, HandlerMethod> getMappings() {
  129. return this.mappingLookup;
  130. }
  131. /**
  132. * Return matches for the given URL path. Not thread-safe.
  133. * @see #acquireReadLock()
  134. */
  135. @Nullable
  136. public List<T> getMappingsByUrl(String urlPath) {
  137. return this.urlLookup.get(urlPath);
  138. }
  139. /**
  140. * Return handler methods by mapping name. Thread-safe for concurrent use.
  141. */
  142. public List<HandlerMethod> getHandlerMethodsByMappingName(String mappingName) {
  143. return this.nameLookup.get(mappingName);
  144. }
  145. /**
  146. * Return CORS configuration. Thread-safe for concurrent use.
  147. */
  148. public CorsConfiguration getCorsConfiguration(HandlerMethod handlerMethod) {
  149. HandlerMethod original = handlerMethod.getResolvedFromHandlerMethod();
  150. return this.corsLookup.get(original != null ? original : handlerMethod);
  151. }
  152. /**
  153. * Acquire the read lock when using getMappings and getMappingsByUrl.
  154. */
  155. public void acquireReadLock() {
  156. this.readWriteLock.readLock().lock();
  157. }
  158. /**
  159. * Release the read lock after using getMappings and getMappingsByUrl.
  160. */
  161. public void releaseReadLock() {
  162. this.readWriteLock.readLock().unlock();
  163. }
  164. public void register(T mapping, Object handler, Method method) {
  165. this.readWriteLock.writeLock().lock();
  166. try {
  167. HandlerMethod handlerMethod = createHandlerMethod(handler, method);
  168. assertUniqueMethodMapping(handlerMethod, mapping);
  169. this.mappingLookup.put(mapping, handlerMethod);
  170. List<String> directUrls = getDirectUrls(mapping);
  171. for (String url : directUrls) {
  172. this.urlLookup.add(url, mapping);
  173. }
  174. String name = null;
  175. if (getNamingStrategy() != null) {
  176. name = getNamingStrategy().getName(handlerMethod, mapping);
  177. addMappingName(name, handlerMethod);
  178. }
  179. CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
  180. if (corsConfig != null) {
  181. this.corsLookup.put(handlerMethod, corsConfig);
  182. }
  183. this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
  184. }
  185. finally {
  186. this.readWriteLock.writeLock().unlock();
  187. }
  188. }
  189. private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) {
  190. HandlerMethod handlerMethod = this.mappingLookup.get(mapping);
  191. if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
  192. throw new IllegalStateException(
  193. "Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" +
  194. newHandlerMethod + "\nto " + mapping + ": There is already '" +
  195. handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
  196. }
  197. }
  198. private List<String> getDirectUrls(T mapping) {
  199. List<String> urls = new ArrayList<>(1);
  200. for (String path : getMappingPathPatterns(mapping)) {
  201. if (!getPathMatcher().isPattern(path)) {
  202. urls.add(path);
  203. }
  204. }
  205. return urls;
  206. }
  207. private void addMappingName(String name, HandlerMethod handlerMethod) {
  208. List<HandlerMethod> oldList = this.nameLookup.get(name);
  209. if (oldList == null) {
  210. oldList = Collections.emptyList();
  211. }
  212. for (HandlerMethod current : oldList) {
  213. if (handlerMethod.equals(current)) {
  214. return;
  215. }
  216. }
  217. List<HandlerMethod> newList = new ArrayList<>(oldList.size() + 1);
  218. newList.addAll(oldList);
  219. newList.add(handlerMethod);
  220. this.nameLookup.put(name, newList);
  221. }
  222. public void unregister(T mapping) {
  223. this.readWriteLock.writeLock().lock();
  224. try {
  225. MappingRegistration<T> definition = this.registry.remove(mapping);
  226. if (definition == null) {
  227. return;
  228. }
  229. this.mappingLookup.remove(definition.getMapping());
  230. for (String url : definition.getDirectUrls()) {
  231. List<T> list = this.urlLookup.get(url);
  232. if (list != null) {
  233. list.remove(definition.getMapping());
  234. if (list.isEmpty()) {
  235. this.urlLookup.remove(url);
  236. }
  237. }
  238. }
  239. removeMappingName(definition);
  240. this.corsLookup.remove(definition.getHandlerMethod());
  241. }
  242. finally {
  243. this.readWriteLock.writeLock().unlock();
  244. }
  245. }
  246. private void removeMappingName(MappingRegistration<T> definition) {
  247. String name = definition.getMappingName();
  248. if (name == null) {
  249. return;
  250. }
  251. HandlerMethod handlerMethod = definition.getHandlerMethod();
  252. List<HandlerMethod> oldList = this.nameLookup.get(name);
  253. if (oldList == null) {
  254. return;
  255. }
  256. if (oldList.size() <= 1) {
  257. this.nameLookup.remove(name);
  258. return;
  259. }
  260. List<HandlerMethod> newList = new ArrayList<>(oldList.size() - 1);
  261. for (HandlerMethod current : oldList) {
  262. if (!current.equals(handlerMethod)) {
  263. newList.add(current);
  264. }
  265. }
  266. this.nameLookup.put(name, newList);
  267. }
  268. }

spring 5.1.2 mvc RequestMappingHandlerMapping 源码初始化过程的更多相关文章

  1. spring 3.1.1 mvc HanderMapping源码

    https://my.oschina.net/zhangxufeng/blog/2177464 RequestMappingHandlerMapping getMappingForMethod /** ...

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

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

  3. 涨姿势:Spring Boot 2.x 启动全过程源码分析

    目录 SpringApplication 实例 run 方法运行过程 总结 上篇<Spring Boot 2.x 启动全过程源码分析(一)入口类剖析>我们分析了 Spring Boot 入 ...

  4. Spring 循环引用(二)源码分析

    Spring 循环引用(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环引用相关文章: & ...

  5. Spring Boot REST(二)源码分析

    Spring Boot REST(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) SpringBoot RE ...

  6. Spring Boot 2.x 启动全过程源码分析

    Spring Boot 2.x 启动全过程源码分析 SpringApplication 实例 run 方法运行过程 上面分析了 SpringApplication 实例对象构造方法初始化过程,下面继续 ...

  7. Spring Boot Dubbo 应用启停源码分析

    作者:张乎兴 来源:Dubbo官方博客 背景介绍 Dubbo Spring Boot 工程致力于简化 Dubbo | grep tid | grep -v "daemon" tid ...

  8. Spring第四天,BeanPostProcessor源码分析,彻底搞懂IOC注入及注解优先级问题!

  9. spring security之 默认登录页源码跟踪

    spring security之 默认登录页源码跟踪 ​ 2021年的最后2个月,立个flag,要把Spring Security和Spring Security OAuth2的应用及主流程源码研究透 ...

随机推荐

  1. SQL Server 常用SQL

    --查询所有表 select * from sysobjects where xtype='u' ORDER BY name ASC

  2. 7、...arg ...[1,2,3] 数组扩展

    1.将离散的参数转成数组 2.将数组拆成单个离散的值 https://blog.csdn.net/qq_30100043/article/details/53391308 箭头函数写法 函数名 -&g ...

  3. JS工具类

    封装了开发中常用的操作 并添加了一些扩展方法供调用 var util = { //获取Url中的参数(不支持中文) getParams: function() { var url = location ...

  4. WPF常用布局介绍

    概述:本文简要介绍了WPF中布局常用控件及布局相关的属性 1 Canvas Canvas是一个类似于坐标系的面板,所有的元素通过设置坐标来决定其在坐标系中的位置..具体表现为使用Left.Top.Ri ...

  5. 【系统监控】性能监测 vmstat,mpstat,iostat

    一.系统整体性能监测工具:uptime [root@WebServer ~]# uptime (同w命令输出的第一行信息) 09:40:52 up 5 days, 57 min, 1 user, lo ...

  6. C# 截取两个指定字符串中间的字符串列表

    /// <summary> /// 截取两个指定字符串中间的字符串列表(开始和结束两个字符串不能相同!) /// </summary> /// <param name=& ...

  7. POJ—1321(棋盘问题)

    题目链接:https://cn.vjudge.net/contest/65959#problem/A 入门dfs,给一张地图,由“#”和“.”组成,“#”处可以放棋子,且棋子不能同行同列,问放满所有“ ...

  8. SQL Server数据库中的系统数据库?

    SQL Server的系统数据库分为:master,model,msdb和tempdb 1.Master数据库 Master数据库记录SQL Server系统的所有系统级别信息(表sysobjects ...

  9. 《Java从入门到精通》学习总结4

    1. 程序运行期间,大部分数据都在内存中进行操作,当程序结束时,这些数据将消失. 如果需要将数据永久保存,可使用文件输入流 / 文件输出流与指定的文件建立连接,将需要的数据永久保存到文件中. File ...

  10. 机器学习入门-BP神经网络模型及梯度下降法-2017年9月5日14:58:16

    BP(Back Propagation)网络是1985年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一. B ...