SpringBoot自动配置原理解析(四)

简介: SpringBoot自动配置原理解析(四)

关联博文:

SpringBoot自动配置原理解析(一)

SpringBoot自动配置原理解析(二)

SpringBoot自动配置原理解析(三)

SpringBoot自动配置原理解析(四)


SpringBoot自动配置原理解析(五)

SpringBoot中如何将@Bean方法解析为BeanDefinition?


接上文SpringBoot自动配置原理解析(三)后,我们本文开始分析this.reader.loadBeanDefinitions(configClasses);。也就是ConfigurationClassBeanDefinitionReader的loadBeanDefinitions方法。

也就是在这个方法里面,对前面没有处理的@Bean注解的method、配置类引入的 比如AutoConfigurationPackages.Registrar以及扫描得到的XXXXAutoConfiguration做了处理。


【1】ConfigurationClassBeanDefinitionReader

如下所示,首先实例化一个TrackedConditionEvaluator ,然后对每个ConfigurationClass 执行loadBeanDefinitionsForConfigurationClass方法。

// ConfigurationClassBeanDefinitionReader
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
  TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
  for (ConfigurationClass configClass : configurationModel) {
    loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
  }
}

① loadBeanDefinitionsForConfigurationClass

loadBeanDefinitionsForConfigurationClass方法如下所示:

// ConfigurationClassBeanDefinitionReader
private void loadBeanDefinitionsForConfigurationClass(
    ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//判断是否跳过当前configClass,如果跳过则从registry importRegistry移除数据
  if (trackedConditionEvaluator.shouldSkip(configClass)) {
    String beanName = configClass.getBeanName();
    if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
      this.registry.removeBeanDefinition(beanName);
    }
    this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
    return;
  }
// 如果当前类是通过@Import导入或者是某个配置类的内部类或者扫描得到的XXXAutoConfiguration
  if (configClass.isImported()) {
  // 注册configClass自身作为一个BeanDefinition放到beanDefinitionMap中
    registerBeanDefinitionForImportedConfigurationClass(configClass);
  }
  // 遍历配置类持有的BeanMethod,注册BeanDefinition到beanDefinitionMap中
  for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    loadBeanDefinitionsForBeanMethod(beanMethod);
  }
//获取配置类持有的importedResources,解析配置文件加载BeanDefinition
//如果你使用了@ImportResource(locations = {"classpath:beans.xml"}),这里就会解析beans.xml文件
  loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//获取配置类持有的importBeanDefinitionRegistrars,触发其registerBeanDefinitions方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}


梳理逻辑如下:


判断是否跳过当前configClass,如果跳过则从registry importRegistry移除数据

如果当前类是通过@Import导入或者是某个配置类的内部类或者是spring.factories扫描得到的xxxAutoConfiguration,则注册configClass自身作为一个BeanDefinition放到beanDefinitionMap中

遍历配置类持有的BeanMethod,注册BeanDefinition到beanDefinitionMap中

获取配置类持有的importedResources,解析配置文件加载BeanDefinition。如果你使用了@ImportResource(locations = {"classpath:beans.xml"}),这里就会解析beans.xml文件

获取配置类持有的importBeanDefinitionRegistrars,触发其registerBeanDefinitions方法

② loadBeanDefinitionsFromRegistrars

loadBeanDefinitionsFromRegistrars方法如下所示,对每一个Entry触发registrar的registerBeanDefinitions方法。

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
  registrars.forEach((registrar, metadata) ->
      registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}


我们以AutoConfigurationPackages.Registrar为例,这里会来到registerBeanDefinitions方法。


我们继续往下看AutoConfigurationPackages的register方法,本文这里只是实例化得到一个GenericBeanDefinition 并注册到registry中。

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
  if (registry.containsBeanDefinition(BEAN)) {
    BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
    ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
    constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
  }
  else {
    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(BasePackages.class);
    beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(BEAN, beanDefinition);
  }
}


如下图所示,注册的beanName与beanDefinition。


也就是说这个方法以编程方式注册自动配置包名称。您可以使用此方法手动定义将用于给定BeanDefinitionRegistry的基本包。通常,建议不要直接调用此方法,而是依赖默认约定,其中包名是从@EnableAutoConfiguration配置类设置的。

【2】bean的实例化

如下所示,当我们do…while执行完毕后,我们有了442个BeanDefinition。


这些BeanDefinition在什么时候实例化呢?大部分在如下两个方法中:

//实例化BeanPostProcessor
registerBeanPostProcessors(beanFactory);
//实例化非懒加载的单例
finishBeanFactoryInitialization(beanFactory);


关于这两个方法可以参考博文SpringBoot启动流程分析之refresh方法详解

目录
相关文章
|
16天前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
2月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
731 0
|
2月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
560 0
|
9天前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
159 4
|
16天前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
探索Spring Boot的@Conditional注解的上下文配置
|
9天前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
187 0
|
1月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
677 10
|
2月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
2月前
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
484 5
|
2月前
|
Java 关系型数据库 数据库连接
Spring Boot项目集成MyBatis Plus操作PostgreSQL全解析
集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步骤与 MyBatis 类似,只不过在 MyBatis Plus 中提供了更多的便利功能,如自动生成 SQL、分页查询、Wrapper 查询等。
257 3

推荐镜像

更多
  • DNS