前言
springboot的设计解决了spring的一些问题,比如自动配置,打包等,说spring-boot-starter自动配置之前,一定要先回顾一次springboot的自动配置原理,它们之间的联系可谓十分紧密。
正文
Spring Boot 的自动配置原理关键点和核心组件的详细解析
1. @SpringBootApplication
注解
@SpringBootApplication
是一个复合注解,包含了 @EnableAutoConfiguration
、@ComponentScan
和 @Configuration
注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
// 省略代码
}
2. @EnableAutoConfiguration
注解
@EnableAutoConfiguration
是自动配置的核心注解,它启用了 Spring Boot 的自动配置机制:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 省略代码
}
3. AutoConfigurationImportSelector
类
@EnableAutoConfiguration
注解通过 AutoConfigurationImportSelector
类来选择并导入自动配置类:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// 省略代码
}
AutoConfigurationImportSelector
实现了 DeferredImportSelector
接口,该接口允许在所有 @Configuration
类都处理完之后再进行导入操作。
4. spring.factories
文件
AutoConfigurationImportSelector
的 selectImports
方法会读取 spring.factories
文件中的配置来获取所有的自动配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfig.ExampleAutoConfiguration,\
...
spring.factories
文件位于 META-INF
目录下,列出了所有可用的自动配置类。
5. 条件注解(Conditional Annotations)
在自动配置类中,使用了大量的条件注解来控制配置的生效条件:
@ConditionalOnClass
:类路径中存在指定的类时生效。@ConditionalOnMissingBean
:容器中不存在指定的 Bean 时生效。@ConditionalOnProperty
:指定的配置属性存在且符合预期时生效。@ConditionalOnResource
:类路径中存在指定的资源时生效。@ConditionalOnBean
:容器中存在指定的 Bean 时生效。@ConditionalOnMissingClass
:类路径中不存在指定的类时生效。
例如:
@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {
// 数据源自动配置代码
}
6. @ConfigurationProperties
注解
自动配置类通常会绑定一些配置属性,通过 @ConfigurationProperties
注解来实现:
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
private String url;
private String username;
private String password;
// 省略代码
}
这些属性可以在 application.properties
或 application.yml
文件中进行配置。
7. @EnableConfigurationProperties
注解
在自动配置类中,通过 @EnableConfigurationProperties
注解启用属性绑定:
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
// 自动配置代码
}
8. 自定义自动配置
开发者可以创建自己的自动配置类,并通过定义自己的 spring.factories
文件来实现自定义的自动配置逻辑:
// 自定义自动配置类
@Configuration
public class MyAutoConfiguration {
// 自定义配置代码
}
// 定义 spring.factories 文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfig.MyAutoConfiguration
9. 排除自动配置
通过 @SpringBootApplication
注解的 exclude
属性或配置文件中的 spring.autoconfigure.exclude
属性,可以排除特定的自动配置类:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication {
// 主类代码
}
或者在配置文件中:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
总结
Spring Boot 的自动配置机制通过 @EnableAutoConfiguration
注解和 AutoConfigurationImportSelector
类,结合 spring.factories
文件及一系列条件注解,实现了对应用环境的自动探测和配置。通过这些机制,Spring Boot 能够智能地为应用程序提供必要的 Bean 配置,大大简化了 Spring 应用的开发工作。
核中核: AutoConfigurationImportSelector
类解析
。
类的定义和接口实现
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// 类变量和方法
}
接口解析
DeferredImportSelector
:延迟导入选择器,允许在所有@Configuration
类都处理完之后再进行导入操作。BeanClassLoaderAware
:提供ClassLoader
实例。ResourceLoaderAware
:提供ResourceLoader
实例。BeanFactoryAware
:提供BeanFactory
实例。EnvironmentAware
:提供Environment
实例。Ordered
:定义排序顺序。
类变量
private static final String[] NO_IMPORTS = {};
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
private Environment environment;
private AutoConfigurationMetadata autoConfigurationMetadata;
NO_IMPORTS
:空导入数组,通常用于返回空结果。beanClassLoader
:Spring 容器的ClassLoader
。beanFactory
:Spring 容器的BeanFactory
。resourceLoader
:资源加载器。environment
:Spring 环境上下文。autoConfigurationMetadata
:自动配置元数据。
setEnvironment 方法
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
设置环境上下文。
setBeanClassLoader 方法
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
设置类加载器。
setBeanFactory 方法
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
设置 Bean 工厂。
setResourceLoader 方法
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
设置资源加载器。
getOrder 方法
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
返回排序顺序,Ordered.LOWEST_PRECEDENCE
表示最低优先级。
selectImports 方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
选择导入的配置类。首先检查自动配置是否启用,如果未启用,则返回空数组。否则,获取自动配置条目并将其转换为数组。
isEnabled 方法
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getAutoConfigurationEntry(metadata) != null;
}
return true;
}
检查自动配置是否启用,如果类是 AutoConfigurationImportSelector
,则获取自动配置条目是否为空。
getAutoConfigurationEntry 方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
获取自动配置条目。
- 检查是否启用自动配置。
- 获取注解属性。
- 获取候选配置类。
- 去重。
- 获取排除项。
- 检查排除的类。
- 移除排除项。
- 过滤配置类。
- 触发自动配置导入事件。
- 返回
AutoConfigurationEntry
。
getAttributes 方法
private AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
return AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true));
}
获取 EnableAutoConfiguration
注解的属性。
getCandidateConfigurations 方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), 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;
}
获取候选配置类。
- 使用
SpringFactoriesLoader
加载工厂名称。 - 确保配置类不为空。
getExclusions 方法
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> exclusions = new LinkedHashSet<>();
exclusions.addAll(asList(attributes, "exclude"));
exclusions.addAll(asList(attributes, "excludeName"));
return exclusions;
}
获取排除的配置类。
- 从注解属性中获取
exclude
和excludeName
属性。 - 添加到排除集合。
checkExcludedClasses 方法
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
List<String> invalidExcludes = exclusions.stream()
.filter(exclude -> !configurations.contains(exclude))
.collect(Collectors.toList());
Assert.isTrue(invalidExcludes.isEmpty(), () -> "Invalid excludes: " + String.join(",", invalidExcludes));
}
检查排除的类是否有效。
- 过滤出无效的排除类。
- 确保无效的排除类为空。
filter 方法
protected List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
return configurations.stream()
.filter(config -> shouldInclude(config, autoConfigurationMetadata))
.collect(Collectors.toList());
}
过滤配置类。
- 通过
shouldInclude
方法过滤配置类。
shouldInclude 方法
protected boolean shouldInclude(String configuration, AutoConfigurationMetadata autoConfigurationMetadata) {
if (autoConfigurationMetadata.wasProcessed(configuration)) {
return autoConfigurationMetadata.getBoolean(configuration, "match", true);
}
return true;
}
判断是否应包含配置类。
- 如果配置类已处理,则检查其匹配属性。
- 否则返回
true
。
fireAutoConfigurationImportEvents 方法
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = getBeans(AutoConfigurationImportListener.class);
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
listeners.forEach(listener -> listener.onAutoConfigurationImportEvent(event));
}
}
触发自动配置导入事件。
- 获取所有
AutoConfigurationImportListener
实例。 - 如果存在监听器,则创建
AutoConfigurationImportEvent
并通知所有监听器。
getBeans 方法
private <T> List<T> getBeans(Class<T> type) {
if (beanFactory instanceof ListableBeanFactory) {
return new ArrayList<>(((ListableBeanFactory) beanFactory).getBeansOfType(type).values());
}
return Collections.emptyList();
}
获取指定类型的所有 Bean 实例。
- 如果
beanFactory
是ListableBeanFactory
,则获取所有指定类型的 Bean 实例。 - 否则返回空列表。
总结
AutoConfigurationImportSelector
类的主要作用是选择并导入自动配置类。它通过读取 spring.factories
文件,结合一系列条件注解判断和过滤,最终确定需要导入的自动配置类列表,并将其注入 Spring 容器中。这个过程中,还会触发相应的事件,供监听器处理。
精心设计一个 spring-boot-starter
:
-
定义依赖:
- 确定
starter
需要依赖的库和版本。 - 在
pom.xml
中定义这些依赖。
- 确定
-
自动配置:
- 创建一个自动配置类,使用
@Configuration
注解。 - 使用
@ConditionalOnClass
和@ConditionalOnMissingBean
等条件注解,确保只有在特定条件下才会加载配置。 - 使用
@Bean
注解定义需要自动配置的 Bean。
- 创建一个自动配置类,使用
-
配置属性:
- 创建一个配置属性类,使用
@ConfigurationProperties
注解,允许用户通过application.properties
或application.yml
文件配置starter
的行为。
- 创建一个配置属性类,使用
-
资源文件:
- 在
META-INF/spring.factories
文件中声明自动配置类,Spring Boot 会自动加载这些配置。
- 在
-
示例代码:
- 提供一个示例项目,展示如何使用
starter
。
- 提供一个示例项目,展示如何使用
示例:
// AutoConfiguration.java
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}
// MyProperties.java
@ConfigurationProperties(prefix = "my")
public class MyProperties {
private String url;
private String username;
private String password;
// getters and setters
}
// META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration
标签:spring,配置,boot,public,自动,注解,class,starter,configurations
From: https://blog.csdn.net/jsjbrdzhh/article/details/143696628