Spring Boot 的自动装配(Auto-Configuration)是其核心特性之一,它通过条件化配置和类路径扫描,快速实现应用的配置自动化装配。Spring 中 bean 有三种装配机制,分别是:
在 xml 中显式配置;
在 java 中显式配置;
隐式的 bean 发现机制和自动装配。
Spring 的自动装配需要从两个角度来实现,或者说是两个操作:
组件扫描(component scanning):spring 会自动发现应用上下文中所创建的 bean;
自动装配(autowiring):spring 自动满足 bean 之间的依赖,也就是我们说的 IoC/DI;
自动装配原理 Spring Boot 在启动时会扫描所有 jar 包中的 META-INF/spring.factories/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件, 加载文件中配置的类:
1 com.ares.config.ratelimit.RateLimiterAutoConfiguration
在Spring Boot 2.4之前的版本中META-INFO/spring.factories文件:
1 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ares.config.ratelimit.RateLimiterAutoConfiguration
新版本中AutoConfiguration.imports替换spring.factories文件原因:
提高可读性和维护性
增强的性能
增加条件化装配
向生态系统演进
springboot自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector 类来实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @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 {}; }
@AutoConfigurationPackage:将main包下的所有组件注册到容器中
@Import(AutoConfigurationImportSelector.class):加载自动装配类 xxxAutoconfiguration
AutoConfigurationImportSelector AutoConfigurationImportSelector 实现了 ImportSelector 接口,它会:
读取 META-INF/spring.factories(新版本META-INF/spring.factories/org.springframework.boot.autoconfigure.AutoConfiguration.imports) 文件中的配置
筛选出 EnableAutoConfiguration 对应的配置类
过滤掉不符合条件的配置类
将符合条件的配置类返回给 Spring 容器进行加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class AutoConfigurationImportSelector implements DeferredImportSelector , BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { private ConfigurableListableBeanFactory beanFactory; private Environment environment; private ClassLoader beanClassLoader; private ResourceLoader resourceLoader; private ConfigurationClassFilter configurationClassFilter; @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry (configurations, exclusions); }
代码逻辑说明:
判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置。
用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName。
获取需要自动装配的所有配置类,读取META-INF/spring.factories或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。这一步不光是这个依赖下的META-INF/spring.factories被读取到,所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。
这一步经历了getConfigurationClassFilter().filter(configurations)一遍筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效。所以并不是把spring.factories中的配置都加载。
ConditionalOnxxx 自动配置类通常使用条件注解来决定是否生效,常见的条件注解包括:
@ConditionalOnClass:当类路径下有指定的类时
@ConditionalOnMissingClass:当类路径下没有指定的类时
@ConditionalOnBean:当容器中有指定的Bean时
@ConditionalOnMissingBean:当容器中没有指定的Bean时
@ConditionalOnProperty:当配置文件中有指定的属性时
@ConditionalOnWebApplication:当应用是Web应用时
小结 自动装配的执行流程:
Spring Boot 启动时,@SpringBootApplication 注解被解析
@EnableAutoConfiguration 注解导入 AutoConfigurationImportSelector
AutoConfigurationImportSelector 读取 classpath 下所有 jar 包中的 META-INF/spring.factories 文件
找出所有标注了 EnableAutoConfiguration 的配置类
通过条件注解对配置类进行过滤
将符合条件的配置类加载到 Spring 容器中
配置类中定义的 Bean 被创建并注册到容器中
示例
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-autoconfigure-processor</artifactId > <optional > true</optional > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Setter @Getter @NoArgsConstructor @ConfigurationProperties(prefix = "snd.webclient") public class CustomWebClientProperties { private String url; private String serverName; private int connectTimeout = 300 ; private int readTimeout = 3000 ; private boolean enableLogging = false ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CustomWebClientFactory { private final WebClient.Builder webClientBuilder; public CustomWebClientFactory (WebClient.Builder webClientBuilder) { this .webClientBuilder = webClientBuilder; } public WebClient createWebClient () { return webClientBuilder.build(); } public WebClient createWebClient (String baseUrl) { return webClientBuilder.baseUrl(baseUrl).build(); } public WebClient createWebClient (String baseUrl, String serverName) { return webClientBuilder.baseUrl(baseUrl).defaultHeader("server-name" , serverName).build(); } }
定义WebClientFactoryAutoConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 @Configuration @ConditionalOnClass(WebClient.class) @EnableConfigurationProperties(CustomWebClientProperties.class) @AutoConfigureAfter(WebClient.class) public class WebClientFactoryAutoConfiguration { private final Logger logger = LoggerFactory.getLogger(WebClientFactoryAutoConfiguration.class); @Bean @LoadBalanced public WebClient.Builder loadBalancedWebClientBuilder () { return WebClient.builder(); } @Bean @LoadBalanced @ConditionalOnMissingBean CustomWebClientFactory customWebClientFactory (WebClient.Builder webClientBuilder, CustomWebClientProperties properties) { if (properties.getUrl() != null ) { webClientBuilder.baseUrl(properties.getUrl()); } else if (properties.getServerName() != null ) { webClientBuilder.baseUrl(String.format("lb://%s" , properties.getServerName())); } HttpClient httpClient = HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, properties.getConnectTimeout()) .responseTimeout(Duration.ofMillis(properties.getReadTimeout())); webClientBuilder.clientConnector(new ReactorClientHttpConnector (httpClient)); if (properties.isEnableLogging()) { webClientBuilder.filter((request, next) -> { logger.info("Request: {} {}" , request.method(), request.url()); return next.exchange(request); }); } return new CustomWebClientFactory (webClientBuilder); } }
META-INF/spring 在文件org.springframework.boot.autoconfigure.AutoConfiguration.imports中添加:
1 com.ares.config.webclient.WebClientFactoryAutoConfiguration