首页 > 其他分享 >设计之道:spring-boot-starter自动配置

设计之道:spring-boot-starter自动配置

时间:2024-11-11 22:15:38浏览次数:3  
标签:spring 配置 boot public 自动 注解 class starter configurations

前言

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 文件

AutoConfigurationImportSelectorselectImports 方法会读取 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.propertiesapplication.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);
}

获取自动配置条目。

  1. 检查是否启用自动配置。
  2. 获取注解属性。
  3. 获取候选配置类。
  4. 去重。
  5. 获取排除项。
  6. 检查排除的类。
  7. 移除排除项。
  8. 过滤配置类。
  9. 触发自动配置导入事件。
  10. 返回 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;
}

获取候选配置类。

  1. 使用 SpringFactoriesLoader 加载工厂名称。
  2. 确保配置类不为空。

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;
}

获取排除的配置类。

  1. 从注解属性中获取 excludeexcludeName 属性。
  2. 添加到排除集合。

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));
}

检查排除的类是否有效。

  1. 过滤出无效的排除类。
  2. 确保无效的排除类为空。

filter 方法

protected List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
    return configurations.stream()
            .filter(config -> shouldInclude(config, autoConfigurationMetadata))
            .collect(Collectors.toList());
}

过滤配置类。

  1. 通过 shouldInclude 方法过滤配置类。

shouldInclude 方法

protected boolean shouldInclude(String configuration, AutoConfigurationMetadata autoConfigurationMetadata) {
    if (autoConfigurationMetadata.wasProcessed(configuration)) {
        return autoConfigurationMetadata.getBoolean(configuration, "match", true);
    }
    return true;
}

判断是否应包含配置类。

  1. 如果配置类已处理,则检查其匹配属性。
  2. 否则返回 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));
    }
}

触发自动配置导入事件。

  1. 获取所有 AutoConfigurationImportListener 实例。
  2. 如果存在监听器,则创建 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 实例。

  1. 如果 beanFactoryListableBeanFactory,则获取所有指定类型的 Bean 实例。
  2. 否则返回空列表。

总结

AutoConfigurationImportSelector 类的主要作用是选择并导入自动配置类。它通过读取 spring.factories 文件,结合一系列条件注解判断和过滤,最终确定需要导入的自动配置类列表,并将其注入 Spring 容器中。这个过程中,还会触发相应的事件,供监听器处理。

精心设计一个 spring-boot-starter

  1. 定义依赖

    • 确定 starter 需要依赖的库和版本。
    • pom.xml 中定义这些依赖。
  2. 自动配置

    • 创建一个自动配置类,使用 @Configuration 注解。
    • 使用 @ConditionalOnClass@ConditionalOnMissingBean 等条件注解,确保只有在特定条件下才会加载配置。
    • 使用 @Bean 注解定义需要自动配置的 Bean。
  3. 配置属性

    • 创建一个配置属性类,使用 @ConfigurationProperties 注解,允许用户通过 application.propertiesapplication.yml 文件配置 starter 的行为。
  4. 资源文件

    • META-INF/spring.factories 文件中声明自动配置类,Spring Boot 会自动加载这些配置。
  5. 示例代码

    • 提供一个示例项目,展示如何使用 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

相关文章