当前位置: 首页 > web >正文

【Java】springboot的自动配置

        如果你用过 Spring Boot,一定对 “引入依赖就能用” 的体验印象深刻 —— 加个spring-boot-starter-web就有了 Web 环境,这个是 SpringBoot 的自动装配(Auto-Configuration)机制。

自动装配的核心注解

        自动装配的逻辑看似复杂,其实核心流程只有 3 步:触发自动装配 → 加载配置类 → 条件筛选组件。

1. 第一步:触发自动装配 ——@SpringBootApplication 注解。

        Spring Boot 应用的启动类上,都会有一个@SpringBootApplication注解,比如:

@SpringBootApplication
public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.class, args);}
}

        这个注解是 “组合注解”,它的核心功能来自其中的 **@EnableAutoConfiguration**注解,触发了自动装配的整个流程。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 1. 开启自动配置(核心)
@EnableAutoConfiguration
// 2. 扫描当前包及子包的Bean(如@Controller、@Service)
@ComponentScan(excludeFilters = { ... })
// 3. 允许在启动类上定义Bean(如@Bean)
@SpringBootConfiguration
public @interface SpringBootApplication {// 省略属性...
}

其中,@EnableAutoConfiguration 是自动装配的 “总开关”,它又依赖两个关键机制:​

  • @Import(AutoConfigurationImportSelector.class):导入一个 “配置选择器”,负责加载自动配置类;​
  • SpringFactoriesLoader:Spring 的一个工具类,负责从指定文件中加载配置类列表。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

2. 第二步:加载配置类 —— 从 META-INF/spring.factories 中加载配置

        AutoConfigurationImportSelector的核心作用,是通过SpringFactoriesLoader,加载classpath 下所有 META-INF/spring.factories 文件中配置的 “自动配置类”。

        (1)什么是 spring.factories?​

        这是一个键值对格式的配置文件,Spring Boot 的核心 starter(如mybatis-pus)中就自带这个文件,路径在:mybatis-plus-boot-starter\3.5.2\mybatis-plus-boot-starter-3.5.2.jar!\META-INF\spring.factories:

(2)AutoConfigurationImportSelector 的工作流程​

当应用启动时,AutoConfigurationImportSelector会执行以下操作:​

        1、调用selectImports()方法,触发配置类加载;​

// 方法作用:选择需要导入的自动配置类,返回类的全限定名数组
public String[] selectImports(AnnotationMetadata annotationMetadata) {// 第一步:判断自动装配是否启用// isEnabled方法会检查@EnableAutoConfiguration注解的启用状态if (!this.isEnabled(annotationMetadata)) {// 如果未启用,返回空数组(NO_IMPORTS是Spring定义的空数组常量)return NO_IMPORTS;} else {// 第二步:获取自动配置条目(核心逻辑)// 该方法会加载、筛选并确定最终需要生效的配置类AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
}

        2、调用getAutoConfigurationEntry()方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} // 获取 @EnableAutoConfiguration 注解的属性(如 exclude、excludeName 等)AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 加载所有候选自动配置类(数据源:META-INF/spring.factories)// 调用我们之前解析过的 getCandidateConfigurations 方法,获取原始候选配置类列表List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);
spring.autoconfigure.excludeSet<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);
@ConditionalOnClass、@ConditionalOnBean)configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);
}

        3、调用getCandidateConfigurations()方法

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 第一个参数:指定加载的工厂类类型(这里是EnableAutoConfiguration.class)// 第二个参数:类加载器(用于读取类路径下的资源)List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(),  // 返回EnableAutoConfiguration.classthis.getBeanClassLoader()                    // 获取当前的类加载器);// 如果为空,抛出异常提示(通常是因为找不到META-INF/spring.factories文件)Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. " +"If you are using a custom packaging, make sure that file is correct.");return configurations;
}protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
}

3. 第三步:条件筛选@Conditiona

加载到自动配置类后,Spring Boot 并不是无条件地启用所有配置,而是通过条件注解进行筛选。

常用的条件注解有:

  • @ConditionalOnClass:当类路径中存在指定类时生效
  • @ConditionalOnMissingClass:当类路径中不存在指定类时生效
  • @ConditionalOnBean:当容器中存在指定 Bean 时生效
  • @ConditionalOnMissingBean:当容器中不存在指定 Bean 时生效
  • @ConditionalOnProperty:当指定的属性有特定值时生效
  • @ConditionalOnWebApplication:当应用是 Web 应用时生效

例如:

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {// 配置内容...
}

自定义自动配置

1、定义我们需要装配的类

结构:

DataSourceAutoconfiguration类

@Configuration
@EnableConfigurationProperties(DataSourcePropertie.class) // 批量注入
public class DataSourceAutoconfiguration {@Bean()public DataSource dataSource(DataSourcePropertie dataSourcePropertie) {try {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();comboPooledDataSource.setJdbcUrl(dataSourcePropertie.getJdbcUrl());comboPooledDataSource.setDriverClass(dataSourcePropertie.getDriverName());comboPooledDataSource.setUser(dataSourcePropertie.getUsernames());comboPooledDataSource.setPassword(dataSourcePropertie.getPasswords());return comboPooledDataSource;} catch (PropertyVetoException e) {throw new RuntimeException(e);}}
}

DataSourcePropertie

@ConfigurationProperties(prefix = "datasouce")// 注入前缀为datasouce
public class DataSourcePropertie {private String jdbcUrl = "jdbc:mysql://localhost:3306/summer_practice";private String driverName = "com.mysql.cj.jdbc.Driver";private String usernames = "root1";private String passwords = "1234561";public String getJdbcUrl() {return jdbcUrl;}public void setJdbcUrl(String jdbcUrl) {this.jdbcUrl = jdbcUrl;}public String getDriverName() {return driverName;}public void setDriverName(String driverName) {this.driverName = driverName;}public String getUsernames() {return usernames;}public void setUsernames(String usernames) {this.usernames = usernames;}public String getPasswords() {return passwords;}public void setPasswords(String passwords) {this.passwords = passwords;}
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.ape.redisspringbootautoconfigure.DataSourceAutoconfiguration

pom.xml

    </properties><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency><!--c3p0--><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>

2、配置咋们的启动类(我们只需要在pom.xml中导入需要装配类的坐标)

结构:

pom.xml

        <dependency><groupId>com.ape</groupId><artifactId>redis-spring-boot-autoconfigure</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

3、在启动类中就可以拿到我们自定义的配置类

@SpringBootApplication
public class SpringbootStarter04Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringbootStarter04Application.class, args);DataSource bean = context.getBean(DataSource.class);System.out.println(bean);}}

4、配置文件(可选)

        由于我们在需要装配的类中添@EnableConfigurationProperties(DataSourcePropertie.class)该注解,所以我们可以在启动类中配置yml文件来替换需要装配的类的数据,从而实现动态的改变其中的数据。

yml

datasouce:usernames: rootpasswords: 123456

总结

        Spring Boot 的自动装配机制通过@EnableAutoConfiguration注解、SpringFactoriesLoader加载机制以及条件注解,实现了基于约定的自动配置,极大地简化了 Spring 应用的开发。允许我们通过自定义配置来覆盖默认行为,可以实现个性化定制。

http://www.xdnf.cn/news/18798.html

相关文章:

  • 谷德红外温度传感器在 3D 打印领域应用探究
  • Rust 登堂 生命周期(一)
  • 纯血鸿蒙下的webdav库
  • 最近遇到的几个JVM问题
  • JVM OOM问题排查与解决思路
  • Flask蓝图:模块化开发的利器
  • HarmonyOS NEXT系列之元服务框架ASCF
  • 第04章 SPSS简介与数据库构建
  • 【机器学习】9 Generalized linear models and the exponential family
  • BQTLOCK 勒索软件即服务出现,拥有复杂的规避策略
  • 大白话解析:多证明验证(Merkle Multi-Proof)​
  • 可视化-模块1-HTML-03
  • 基于SpringBoot的美食分享平台【2026最新】
  • 构建wezzer平台!
  • Indy HTTP Server 使用 OpenSSL 3.0
  • 知识蒸馏 Knowledge Distillation 1. 监督式微调(SFT):极大似然是前向 KL 的特例
  • Grafana k6 性能测试
  • 深度模块化剖析:构建一个健壮的、支持动态Cookie和代理的Python网络爬虫
  • 保姆级Maven安装与配置教程(Windows版)
  • 基于 MATLAB 的信号处理实战:滤波、傅里叶变换与频谱分析
  • 从文本树到结构化路径:解析有限元项目架构的自动化之道
  • 服务器硬件电路设计之 SPI 问答(四):3 线 SPI、Dual SPI 与 Qual SPI 的奥秘
  • Leetcode 3660. Jump Game IX
  • k8sday16调度器
  • MSF基础知识
  • Java 内存模型(JMM)与并发可见性:深入理解多线程编程的基石
  • Java:HashMap的使用
  • K8s 实战:六大核心控制器
  • 什么是 Nonce?
  • 电力电子simulink练习10:反激Flyback电路搭建