目录
SpringBoot 的核心优势之一是 "自动配置"(Auto-configuration),它让开发者无需手动编写大量 XML 或 Java 配置就能快速搭建应用。本文将从底层原理出发,详细拆解自动配置的实现机制。
Conditional
条件化注解(如@ConditionalOnClass, @ConditionalOnBean等):这类注解允许开发者定义特定条件下才激活的配置规则。例如,只有当指定类存在于当前类路径下时,相关的bean才会被创建和配置,从而实现更加灵活且针对性强的自动配置策略。
自定义条件:
① 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判 断,返回 boolean值 。
matches 方法两个参数:
• context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
• metadata:元数据对象,用于获取注解属性。
② 判断条件: 在初始化Bean时,使用 @Conditional(条件类.class)注解
SpringBoot 提供的常用条件注解: 以下注解在springBoot-autoconfigure的condition包下 ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean ConditionalOnBean:判断环境中有对应Bean才初始化Bean
@Enable注解
SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理是使用@Import注 解导入一些配置类,实现Bean的动态加载
@Import注解
@Enable底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。 而@Import提供4中用法:
① 导入Bean
② 导入配置类
③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类
④ 导入 ImportBeanDefinitionRegistrar 实现类。
@EnableAutoConfiguration 注解
主启动类
//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//以为是启动了一个方法,没想到启动了一个服务
SpringApplication.run(SpringbootApplication.class, args);
}
}
@SpringBootApplication注解内部
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// ......
}
@ComponentScan
这个注解在Spring中很重要 ,它对应XML配置中的元素。 作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
@SpringBootConfiguration
作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;
//@SpringBootConfiguration注解内部
//这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
@Configuration
public @interface SpringBootConfiguration {}
//里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用
@Component
public @interface Configuration {}
@AutoConfigurationPackage :自动配置包
/AutoConfigurationPackage的子注解
//Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@EnableAutoConfiguration开启自动配置功能:以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效。
@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;
@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 {};
}
AutoConfigurationImportSelector.class
↓
selectImports方法
↓
this.getAutoConfigurationEntry(annotationMetadata)方法
↓
this.getCandidateConfigurations(annotationMetadata, attributes)方法
↓
方法体:
List<String> configurations =
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass
(), this.getBeanClassLoader());
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;
↓
在所有包名叫做autoConfiguration的包下面都有META-INF/spring.factories文件
总结原理
@EnableAutoConfiguration 注解内部使用@Import(AutoConfigurationImportSelector.class) 来加载配置类。 配置文件位置:META-INF/spring.factories,该配置文件中定义了大量的配置类,当 SpringBoot 应用启动时,会自动加载这些配置类,初始化Bean 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean。
自定义启动器
需求: 自定义datasource-starter,要求当导入其坐标时,SpringBoot自动创建DataSource的Bean
实现步骤:
创建datasource_springboot_autoconfig模块
创建datasource_springboot_starter模块,依赖datasource_springboot_autoconfig的模块
在datasource_springboot_autoconfig模块中初始化datasource,并定义META-INF/spring.factories文件 在测试模块中引入自定义的datasource_springboot_starter依赖,测试获取datasource的Bean。
datasource_springboot_autoconfig目录层级:
pom.xml:
<dependencies>
<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>
<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>
</dependencies>
【注意:这里usernames和passwords故意填写错误,看是否会用到自己配置的usernames和passwords】
@ConfigurationProperties(prefix = "datasource")
public class DataSourceProperties {
private String jdbcUrl="jdbc:mysql://127.0.0.1:3306/lzl";
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;
}
}
@ConfigurationProperties(prefix = "datasource"):是 Spring Boot 中的一个注解,用于将配置文件(如 application.properties
或 application.yml
)中以指定前缀(这里是 datasource
)开头的配置项绑定到 Java 类的属性上。
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
public DataSource dataSource(DataSourceProperties dataSourceProperties){
try {
ComboPooledDataSource comboPooledDataSource=new ComboPooledDataSource();
comboPooledDataSource.setJdbcUrl(dataSourceProperties.getJdbcUrl());
comboPooledDataSource.setDriverClass(dataSourceProperties.getDriverName());
comboPooledDataSource.setUser(dataSourceProperties.getUsernames());
comboPooledDataSource.setPassword(dataSourceProperties.getPasswords());
return comboPooledDataSource;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}
@EnableConfigurationProperties(DatasourceProperties.class)用于启用指定类的 @ConfigurationProperties
功能。如果一个类使用了 @ConfigurationProperties
但未被 Spring 容器管理(例如未加 @Component
),则需要通过该注解显式指定该类,使其属性能与配置文件绑定。
META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ape.DataSourceAutoConfiguration
datasource_springboot_starter:
pom.xml:
springboot_starter_test:
pom.xml:
application.yml:
datasource:
usernames: root
passwords: 123456
启动类:
@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);
}
}
输出结果: