SpringBoot 自动装配
1 SPI
要了解SpringBoot的自动配置原理,我们必须先来了解SPI机制
SPI(Service Provider Interface),是JDK内置的一种 服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。
SPI 示例
1) 目录结构

2) 新建接口Search
package com.cqsiri.spi;
public interface Search {
void test();
}3) 创建实现类SearchImpl
package com.cqsiri.spi;
public class SearchImpl implements Search{
@Override
public void test() {
System.out.println("SearchImpl#test()");
}
}4. 在resource下创建META-INF目录,META-INF下创建services目录。
创建接口的全限定类名的文件com.cqsiri.spi.Search,内容为需要加载的实现类的全限定类名,可以是多个实现类
5. 测试类
package com.cqsiri;
import com.cqsiri.spi.Search;
import java.util.Iterator;
import java.util.ServiceLoader;
public class SPITest {
public static void main(String[] args) {
ServiceLoader<Search> load = ServiceLoader.load(Search.class);
Iterator<Search> iterator = load.iterator();
while (iterator.hasNext()) {
Search next = iterator.next();
next.test();
}
}
}6) 测试结果
测试类控制台结果,打印了SearchImpl类实现的方法

2 Springboot的SPI
Spring Boot 对SPI机制这一概念进行了扩展,以支持其自动配置和模块化架构。
Spring Boot 利用 spring.factories 文件,这个文件列出了与自动配置相关的接口及其实现类,Spring Boot 启动时会加载这些配置。

2.1 @SpringBootApplication
在启动类上加上SpringBootApplication注解,SpringBoot就会为我们自动装配。
SpringBootApplicatioin注解上又有SpringBootConfiguration,EnableAutoConfiguration,ComponentScan三个注解
//表示这是一个配置类
@SpringBootConfiguration
//打开自动装配
@EnableAutoConfiguration
//组件扫描
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}2.2 @SpringBootConfiguration注解
@Configuration //表明是一个配置注解
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}2.3 @ComponentScan注解
@ComponentScan注解是用来进行组件扫描的,扫描启动类所在的包及其子包下所有被@Component及其衍生注解声明的类。
SpringBoot启动类,之所以具备扫描包功能,就是因为包含了@ComponentScan注解。
2.4 @EnableAutoConfiguration注解(自动配置核心注解)
@AutoConfigurationPackage
/*
* 导入ImportSelector接口实现类
*/
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}AutoConfigurationImportSelector类中重写了ImportSelector接口的selectImports()方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}selectImports()方法底层调用getAutoConfigurationEntry()方法,获取可自动配置的配置类信息集合
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//getCandidateConfigurations(annotationMetadata, attributes)方法获取在配置文件中配置的所有自动配置类的集合
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}getAutoConfigurationEntry()方法通过调用getCandidateConfigurations(annotationMetadata, attributes)方法获取在配置文件中配置的所有自动配置类的集合
/*
* getCandidateConfigurations方法的功能:
* 获取所有基于META-INF/spring.factories文件中配置类的集合
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}当SpringBoot程序启动时,就会加载配置文件当中所定义的配置类,并将这些配置类信息(类的全限定名)封装到String类型的数组中,最终通过@Import注解将这些配置类全部加载到Spring的IOC容器中,交给IOC容器管理。
