SpringBoot 自动配置原理

SpringBoot 自动配置原理

application.properties 配置是如何在 Spring Boot 项目中生效的呢?

扫描 spring.factories 文件

Spring Boot 关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中。@SpringBootApplication 引用了 @EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
}

@EnableAutoConfiguration 引入了 AutoConfigurationImportSelector.class

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
}

AutoConfigurationImportSelectorselectImports 方法通过 SpringFactoriesLoader.loadFactoryNames() 扫描所有具有 META-INF/spring.factories 的 jar 包。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

// AutoConfigurationImportSelector.java
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    return configurations;
}

这个 spring.factories 文件是一组一组的 key=value 的形式,其中一个 key 是 org.springframework.boot.autoconfigure.EnableAutoConfiguration,这个 key 对应的 value 是以逗号分隔的各种配置类的全称

找到所有这些配置类后,会将这些自动配置类加载到 Spring 容器中。

自动配置生效

每一个 XxxxAutoConfiguration 自动配置类都是在某些条件之下才会生效的,这些条件的限制在 Spring Boot 中以注解的形式体现。以 ServletWebServerFactoryAutoConfiguration 为例,它上面有一些 ConditionalOnClassConditionalOnWebApplication 等条件,这个配置才会生效:

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
}

在它上面还有一个 EnableConfigurationProperties 配置项,其参数是 ServerProperties,在这个类中其通过 ConfigurationProperties 从配置文件中读取 server.port 的值,然后绑定到 ServerProperties 上,并通过 EnableConfigurationProperties 导入到 Spring 容器中:

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	private Integer port;

	private InetAddress address;

}

总结

Spring Boot 启动的时候会通过 @EnableAutoConfiguration 注解找到 META-INF/spring.factories 配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以 AutoConfiguration 结尾来命名的,它实际上就是一个JavaConfig 形式的 Spring 容器配置类,它能通过以 Properties 结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而 XxxxProperties 类是通过 @ConfigurationProperties 注解与全局配置文件中对应的属性进行绑定的。

参考