目录
1、自动配置原理(基于springboot 3.0 版本)
2、自动配置中注解
3、自定义 starter
3.1、定义 pom.xml 文件
3.2、定义属性类
3.3、编写自动配置类,使用容器中的属性类读取配置文件中的属性值。
3.4、定义实体类
3.5、编写自动配置文件
4、引入自定义的 starter ,并且测试自动配置功能
4.1、pom.xml
4.2、配置文件 application.yml
4.3、主启动类
SpringBoot 的核心原理就是自动配置,其所有的配置类都是由 spring-boot-autoconfiguration这个模块提供的,自动配置类一般是以 ***AutoConfiguration命名,自动配置类需要注册到自动配置文件中。
自动配置文件:
1)、在 springboot 2.7 之前,自动配置文件在 META-INF/spring.factories (在 springboot 2.7 版本中宣布废弃了)
2)、在 springboot 3.0 之前,老的自动配置文件依旧支持,为了向后兼容;在 springboot 3.0 之后,正式废除,采用新的自动配置文件。新的自动配置文件为:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
springboot 自动配置原理使用是 @EnableAutoConfiguration 注解。
@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 {};
}
1)、@AutoConfigurationPackage:注册需要自动配置的包,如果不指定就是当前注解所在类的包。
2)、@Import({AutoConfigurationImportSelector.class}):导入AutoConfigurationImportSelector配置类。
AutoConfigurationImportSelector配置类实现了ImportSelector 接口
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
// ========================
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
getAutoConfigurationEntry 方法进入 getCandidateConfigurations 方法。
// 自动配置文件路径
private static final String LOCATION = "META-INF/spring/%s.imports";
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List configurations = ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).getCandidates();
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
// ImportCandidates.load 方法
public static ImportCandidates load(Class> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
String location = String.format("META-INF/spring/%s.imports", annotation.getName());
Enumeration urls = findUrlsInClasspath(classLoaderToUse, location);
List importCandidates = new ArrayList();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
importCandidates.addAll(readCandidateConfigurations(url));
}
return new ImportCandidates(importCandidates); // 返回类型:List
}
最后得到将要自动注册到容器中的 对象列表。
1)、@AutoConfiguration : 是 @Configuration(proxyBeanMethods = false),@AutoConfigureBefore,@AutoConfigureAfter 三者的组合,带有这个注解就表示这个是个自动配置类。
2)、@ConditionOn* : 这是一种条件注解,表示在满足指定条件时才会进行自动配置。主要有:@ConditionOnClass,@ConditionOnBean,@ConditionOnProperty;@ConditionOnMissingClass,@ConditionOnMissingBean,@ConditionOnMissingProperty。
3)、排除某个自动配置:@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})。
4)、@SpringBootConfiguration:替代 @Configuration 注解。
5)、@EnableAutoConfiguration:开启自动配置。
这些是主要的注解,足以看懂源码。
自定义一个 starter ,并且使用自动配置功能,帮助彻底搞懂自动配置原理。
4.0.0
com.test
test-spring-boot-starter
1.0
autoconfiguration
autoconfiguration
17
UTF-8
UTF-8
3.0.0
org.springframework.boot
spring-boot-starter
org.projectlombok
lombok
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
17
UTF-8
// 属性类
@Data
@ConfigurationProperties(prefix = "weilong.param")
public class TestProperties {
private String name;
private Integer age;
}
@AutoConfiguration
@ConditionalOnProperty(prefix = "test.enable", name = "isauto", havingValue = "true") // 决定是否被自动注册
@EnableConfigurationProperties({TestProperties.class}) // 将属性类加载到容器
public class TestAutoConfiguration {
@Bean
public TestClass testClass(TestProperties testProperties){
TestClass testClass = new TestClass();
testClass.setAge(testProperties.getAge());
testClass.setName(testProperties.getName());
return testClass;
}
}
@Data
public class TestClass {
private String name;
private Integer age;
public String test(){
return "hello "+ name + " autoConfiguration: " + age;
}
}
在 resources 目录下创建 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,内容如下。
com.test.autoconfiguration.test.TestAutoConfiguration
新建一个模块,导入自定义的 starter
org.springframework.boot
spring-boot-starter
com.test
test-spring-boot-starter
1.0
compile
test:
enable:
isauto: true # 决定是否开启自动配置
param:
name: test
age: 1
启动主启动类,发现 TestClass 不必导入就可以直接使用,说明已经被自动配置。
@SpringBootApplication
@Slf4j
public class AutoCOnfigurationtestApplication {
public static void main(String[] args) {
SpringApplication.run(AutoCOnfigurationtestApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(TestClass testClass){
return args -> log.info(testClass.test());
}
}
总结:以上是自动配置原理解读,通过手写 starter,注册自动配置类 ,进一步理解自动配置原理,还有很多内容没有涉及,需要阅读源码进一步深入细节。
本人是一个从小白自学计算机技术,对运维、后端、各种中间件技术、大数据等有一定的学习心得,想获取自学总结资料(pdf版本)或者希望共同学习,关注微信公众号:it自学社团。后台回复相应技术名称/技术点即可获得。(本人学习宗旨:学会了就要免费分享)