SpringMVC源码剖析2——处理器映射器

1.处理器映射器 HandlerMapping

一句话概括作用: 为 我 们 建 立 起 @RequestMapping 注 解 和 控 制 器 方 法 的 对 应 关 系 。

怎么去查看

第一步:

处理器映射器的实体类:
RequestMappingHandlerMapping   
父类  
RequestMappingInfoHandlerMapping
父类的父类
AbstractHandlerMethodMapping
父类的父类的父类
AbstractHandlerMapping

第二步:找到对应的方法,获取拦截的方法

[Java] 纯文本查看 复制代码

?


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的

[Java] 纯文本查看 复制代码

?


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);

[Java] 纯文本查看 复制代码

?


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);
注册处理程序方法及其唯一映射。在启动时调用

[Java] 纯文本查看 复制代码

?


1

2

3

protected void registerHandlerMethod(Object handler, Method method, T mapping) {

   this.mappingRegistry.register(mapping, handler, method);

}

先加锁,后将方法和映射放入Map中的
register(mapping, handler, method);

[Java] 纯文本查看 复制代码

?


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);

      }

原文地址:https://www.cnblogs.com/zhuxiaopijingjing/p/12262891.html

时间: 2024-10-07 15:21:13

SpringMVC源码剖析2——处理器映射器的相关文章

SpringMVC源码剖析(二)- DispatcherServlet的前世今生

上一篇文章<SpringMVC源码剖析(一)- 从抽象和接口说起>中,我介绍了一次典型的SpringMVC请求处理过程中,相继粉墨登场的各种核心类和接口.我刻意忽略了源码中的处理细节,只列出最简单的类甚至是接口类,目的就是让大家先从最高层次的抽象意义上来审视SpringMVC这个框架:我也刻意将SpringMVC和Struts2做对比,目的是让大家看到,SpringMVC究竟吸取了Sturts2设计思想中的哪些精华,又弥补了它的哪些遗憾. DispatcherServlet作为SpringMV

SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现

SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段.在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过service()方法,委派到doGet()或者doPost()这些方法,完成Http请求的处理. 在初始化流程中,SpringMVC巧妙的运用依赖注入读取参数,并最终建立一个与容器上下文相关联的spring子上下文.这个子上下文,就像Struts2中xwork容器一样,为接下来的Http处理流程中各种编程

SpringMVC源码剖析(五)-消息转换器HttpMessageConverter

SpringMVC源码剖析(五)-消息转换器HttpMessageConverter 目录[-] 概述 Http请求的抽象 HttpInputMessage HttpOutputMessage HttpMessageConverter RequestResponseBodyMethodProcessor 思考 概述 在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Sprin

springMVC非注解常用的&quot;处理器映射器&quot;、&quot;适配器&quot;、&quot;处理器&quot;

非注解处理器映射器1. org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping url 到bean name的映射2. org.springframework.web.servlet.handler.SimpleUrlHandlerMapping url 到bean id的映射 非注解适配器1. org.springframework.web.servlet.mvc.SimpleControllerHandlerAdap

SpringMVC源码阅读:视图解析器

1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC如何完成视图解析的 2.源码分析 在SpringMVC源码阅读:拦截器分析过doDispatch的运行过程,这里再分析一遍 回到DispatcherServlet类的doDispatch方法,看看doDispatch如何获取ModelAndView Hand

SpringMVC源码阅读:异常解析器

1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC如何完成异常解析.捕捉异常,并自定义异常和异常解析器 2.源码分析 进入DispatcherServlet的processDispatchResult方法 1024行判断异常是否是ModelAndViewDefiningException类型,如果是,直接返

SpringMVC源码剖析5:消息转换器HttpMessageConverter与@ResponseBody注解

转自 SpringMVC关于json.xml自动转换的原理研究[附带源码分析] 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Spring源码解析 https://blog.csdn.net/column/details/21851.html 部分代码会放在我的的Github:https://github.com/h2pl/ 目录 前言 现象 源码分析 实例讲解 关于配置 总结 参考资料 前言 SpringMVC是目前主流的Web MVC

SpringMVC源码剖析(一)- 从抽象和接口说起

SpringMVC作为Struts2之后异军突起的一个表现层框架,正越来越流行,相信javaee的开发者们就算没使用过SpringMVC,也应该对其略有耳闻.我试图通过对SpringMVC的设计思想和源码实现的剖析,从抽象意义上的设计层面和实现意义上的代码层面两个方面,逐一揭开SpringMVC神秘的面纱,本文的代码,都是基于spring的 3.1.3RELEASE版本. 任何一个框架,都有自己特定的适用领域,框架的设计和实现,必定是为了应付该领域内许多通用的,烦琐的.基础的工作而生.Sprin

SpringMVC源码剖析(三)- DispatcherServlet的初始化流程

在我们第一次学Servlet编程,学Java Web的时候,还没有那么多框架.我们开发一个简单的功能要做的事情很简单,就是继承HttpServlet,根据需要重写一下doGet,doPost方法,跳转到我们定义好的jsp页面.Servlet类编写完之后在web.xml里注册这个Servlet类. 除此之外,没有其他了.我们启动web服务器,在浏览器中输入地址,就可以看到浏览器上输出我们写好的页面.为了更好的理解上面这个过程,你需要学习关于Servlet生命周期的三个阶段,就是所谓的“init-s