SpringBoot自动配置原理
SpringBoot自动配置原理
SpringBoot在启动过程中,会识别到启动类 将其保存在 SpringApplication 的 mainApplicationClass 属性中,在 SpringApplication 构造方法中指定:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass(); // 识别启动类
}
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
SpringBoot 自动配置有两种方式:
@import
SpringBoot 在启动过程中,会去收集被 @Import 注解的类 作为一个 sourceClass


if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}

就会将类加到 imports 中,为了以后实例化

会在之后解析 xxxAutoConfiguration 中的 @bean ,解析到之后,加入到容器里面
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
读取 spring.factories 配置文件
在 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 的 prosess() 中:
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
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 = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
在 prepareRefresh() 的 load() 方法中,将 启动类 注册到 AnnotatedBeanDefinitionReader 中,以便以后识别
private final AnnotatedBeanDefinitionReader annotatedReader;
private int load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
if (isEligible(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
getCandidateConfigurations() 中调用 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
getBeanClassLoader());
在这里获取 META-INF 目录下 spring.factories 文件中的指定 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration
对应的类的权限定名称。这些类会经过一系列的排除,过滤,最后加入到 IOC 容器中供我们使用
手写一个 starter
-
创建一个 springboot 工程,加入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.7</version> </dependency> -
编写一个 template 类
public class JalivvTemplate { public void say() { System.out.println("jalivv so cool"); } } -
编写一个 AutoConfiguration 类,在该类中将 template 对象注入到 IOC 容器中。
public class JalivvAutoConfiguration { @Bean JalivvTemplate jalivvTemplate() { return new JalivvTemplate(); } } -
编写一个 Selector 类,去实现 ImportSelector 接口,重写接口中的方法
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{JalivvAutoConfiguration.class.getName()}; } } -
编写一个注解,开启这个 starter
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(MyImportSelector.class) public @interface EnableJalivv { } -
引入到我们自己的项目中
<dependency> <groupId>com.jalivv.spring.boot</groupId> <artifactId>jalivv-spring-boot-starter</artifactId> <version>1.0</version> </dependency> -
在启动类加上 @EnableJalivv ,就能从 IOC 容器中 取到 JalivvTemplate 这个对象
RedisAutoconfiguration
redisAutoConfiguration 在 spring.factories 配置文件中已经配置,采用加载该配置文件的方式 加入IOC 容器
# Auto Configure 其他的类已经省略
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
在 redisAutoConfiguration 中,就配置了 RedisTemplate
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}

浙公网安备 33010602011771号