04在spring配置文件中声名HandlerMapping并注册Handler

简介: Spring中bean创建之后执行自定义初始化获取当前所有的bean并过滤得到是处理器的bean为业务Handler创建映射关系

内容概览


  • Spring中bean创建之后执行自定义初始化
  • 获取当前所有的bean并过滤得到是处理器的bean
  • 为业务Handler创建映射关系


spring-beans的InitializingBean


InitializingBean这个接口是spring-beans模块内的接口。该接口定义中就一个方法:


void afterPropertiesSet() throws Exception;


该方法在BeanFactory创建bean之后会被调用,因此可以通过实现该接口做自定义的初始化,或者校验必要的参数是否被设置。


创建Http请求和处理器Handler的映射关系的切入口


Http请求和处理器Handler的映射关系由处理器映射器HandlerMapping来维护,RequestMappingHandlerMapping是处理器映射器的一种实现,该类做了如下两件事情


  1. 创建了Http请求和处理器Handler的映射
  2. 当有Http请求时,可以通过Http请求获取到处理该请求的处理器


由于本篇只描述映射关系的创建,所以下面类关系图中没有体现RequestMappingHandlerMapping对HandlerMapping的实现:



  1. RequestMappingHandlerMapping继承了AbstractHandlerMethodMapping,而AbstractHandlerMethodMapping就实现了InitializingBean接口
  2. 所以当RequestMappingHandlerMapping这个Bean在被创建之后实现了InitializingBean接口中的方法afterPropertiesSet就会被调用


RequestMappingHandlerMapping实例化之后的创建映射关系的执行流程


映射关系创建的时序图



主要代码


AbstractHandlerMethodMapping实现的afterPropertiesSet


   @Override

   public void afterPropertiesSet() throws Exception {

       initHandlerMethods();

   }


AbstractHandlerMethodMapping实现了InitializingBean的afterPropertiesSet方法,当被回调之后调用自己的初始化方法。


AbstractHandlerMethodMapping的initHandlerMethods


   protected void initHandlerMethods() {

       for (String beanName : getCandidateBeanNames()) {

           if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {

               processCandidateBean(beanName);

           }

       }

   }


获取所有的候选Bean,对候选的Bean进行循环遍历并简单的排除


AbstractHandlerMethodMapping的processCandidateBean


   protected void processCandidateBean(String beanName) {

       Class<?> beanType = null;


       try {

           beanType = obtainApplicationContext().getType(beanName);

       } catch (Throwable ex) {

           if (logger.isTraceEnabled()) {

               logger.trace("Could not resolve type for bean '" + beanName + "'", ex);

           }

       }

       if (beanType != null && isHandler(beanType)) {

           detectHandlerMethods(beanName);

       }

   }


对排除之后的候选Bean进行处理,这里会调用isHandler判断当前的Bean是否是处理器类型的Bean。如果是则会处理这个类中的方法。


RequestMappingHandlerMapping的isHandler


   @Override

   protected boolean isHandler(Class<?> beanType) {

       return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||

               AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);

   }


这个方法的逻辑还是很明了的,判断当前Bean的类型是否有Controller注解或者RequestMapping注解。这里就知道为什么业务Handler使用这两个注解标识之后就可以用来处理Http请求了。


AbstractHandlerMethodMapping的detectHandlerMethods


   protected void detectHandlerMethods(Object handler) {

       Class<?> handlerType = (handler instanceof String) ? obtainApplicationContext().getType(((String) handler)) : handler.getClass();


       if (null != handlerType) {

           Class<?> userType = ClassUtils.getUserClass(handlerType);

           Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>)

                   method -> getMappingForMethod(method, handlerType));


           methods.forEach((method, mapping) -> {

               Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);

               registerHandlerMethod(handler, invocableMethod, mapping);

           });

       }

   }


对于是处理器的类,则获取该类的所有映射方法getMappingForMethod。得到所有方法之后进行遍历循环进行注册


获取RequestMappingInfo


 @Override

   @Nullable

   protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {

       RequestMappingInfo info = createRequestMappingInfo(method);

       if (null != info) {

           RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);

           if (null != typeInfo) {

               info = typeInfo.combine(info);

           }

       }

       return info;

   }


   @Nullable

   private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {

       RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);

       RequestCondition<?> condition = element instanceof Class ?

               getCustomTypeCondition((Class<?>) element) :

               getCustomMethodCondition((Method) element);

       return null != requestMapping ? createRequestMappingInfo(requestMapping, condition) : null;

   }


首先根据方法获取RequestMapping信息封装成RequestMappingInfo,然后再获取当前类上的RequestMapping信息,因为RequestMapping既可以作用在方法上又可以作用在类上,当两者上面都有时,需要将两者合并起来。


其他


注册的流程虽然很简单,但是注册的过程需要注意的地方确实很多。特别是RequestMappingInfo的构造,这里先认识下它,在后面根据Http请求查找映射的处理器时还会用到它。

相关文章
|
6月前
|
Java Spring
Spring boot 运行服务jar外配置配置文件方式总结
Spring boot 运行服务jar外配置配置文件方式总结
995 0
|
3月前
|
XML Java 数据格式
Spring从入门到入土(xml配置文件的基础使用方式)
本文详细介绍了Spring框架中XML配置文件的使用方法,包括读取配置文件、创建带参数的构造对象、使用工厂方法和静态方法创建对象、对象生命周期管理以及单例和多例模式的测试。
155 7
Spring从入门到入土(xml配置文件的基础使用方式)
|
7天前
|
Java 测试技术 应用服务中间件
Spring Boot 配置文件总结
Spring Boot 提供全局配置文件 `application.properties` 和 `application.yml`,用于修改自动配置的默认值。前者使用键值对配置,后者使用缩进和冒号。不同环境(开发、测试、生产)可切换配置文件,通过 `spring.profiles.active` 指定。例如,开发环境端口为4790,测试环境为4791,生产环境为4792。配置示例展示了属性、List、Map定义及引用方法。
46 14
|
29天前
|
XML Java 数据格式
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
本文介绍了在使用Spring框架时,如何通过创建`applicationContext.xml`配置文件来管理对象。首先,在resources目录下新建XML配置文件,并通过IDEA自动生成部分配置。为完善配置,特别是添加AOP支持,可以通过IDEA的Live Templates功能自定义XML模板。具体步骤包括:连续按两次Shift搜索Live Templates,配置模板内容,输入特定前缀(如spring)并按Tab键即可快速生成完整的Spring配置文件。这样可以大大提高开发效率,减少重复工作。
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
|
5月前
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
3月前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
3月前
|
Java 测试技术 Spring
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
这篇文章介绍了Spring Boot中配置文件的语法、如何读取配置文件以及如何通过静态工具类读取配置文件。
279 0
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
|
4月前
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
69 10
|
4月前
|
消息中间件 NoSQL 安全
(转)Spring Boot加载 不同位置的 application.properties配置文件顺序规则
这篇文章介绍了Spring Boot加载配置文件的顺序规则,包括不同位置的application.properties文件的加载优先级,以及如何通过命令行参数或环境变量来指定配置文件的名称和位置。
148 0
|
5月前
|
Java Spring 传感器
AI 浪潮席卷,Spring 框架配置文件管理与环境感知,为软件稳定护航,你还在等什么?
【8月更文挑战第31天】在软件开发中,配置文件管理至关重要。Spring框架提供强大支持,便于应对不同环境需求,如电商项目的开发、测试与生产环境。它支持多种格式的配置文件(如properties和YAML),并能根据环境加载不同配置,如数据库连接信息。通过`@Profile`注解可指定特定环境下的配置生效,同时支持通过命令行参数或环境变量覆盖配置值,确保应用稳定性和可靠性。
84 0