# spring boot
# 介绍
# 实现原理
EnableAutoConfiguration注解上有@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
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
AutoConfigurationPackage注解上有@Import(AutoConfigurationPackages.Registrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
2
3
4
5
6
7
8
9
在BeanFactory文章中我们提到@Import会在application context的refresh过程中调用到,执行其中@Import中的AutoConfigurationPackages.Registrar的registerBeanDefinitions方法。
AutoConfigurationPackages.Registrar会注册basePackage下的bean(basePackage通过@AutoConfigurationPackage的basePackages参数传入)或 使用当前注解标注的类的包名)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# AutoConfigurationImportSelector
AutoConfigurationImportSelector的determineImports会查找可以自动配置的Configuration类。
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector implements DeterminableImports {
private static final Set<String> ANNOTATION_NAMES;
static {
Set<String> names = new LinkedHashSet<>();
names.add(ImportAutoConfiguration.class.getName());
names.add("org.springframework.boot.autoconfigure.test.ImportAutoConfiguration");
ANNOTATION_NAMES = Collections.unmodifiableSet(names);
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
List<String> candidateConfigurations = getCandidateConfigurations(metadata, null);
Set<String> result = new LinkedHashSet<>(candidateConfigurations);
result.removeAll(getExclusions(metadata, null));
return Collections.unmodifiableSet(result);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
getCandidateConfigurations最终调用到loadFactoryNames
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> candidates = new ArrayList<>(); Map<Class<?>, List<Annotation>> annotations = getAnnotations(metadata); annotations.forEach( (source, sourceAnnotations) -> collectCandidateConfigurations(source, sourceAnnotations, candidates)); return candidates; } private void collectCandidateConfigurations(Class<?> source, List<Annotation> annotations, List<String> candidates) {
for (Annotation annotation : annotations) {
candidates.addAll(getConfigurationsForAnnotation(source, annotation));
}
}
private Collection<String> getConfigurationsForAnnotation(Class<?> source, Annotation annotation) {
String[] classes = (String[]) AnnotationUtils.getAnnotationAttributes(annotation, true).get("classes");
if (classes.length > 0) {
return Arrays.asList(classes);
}
return loadFactoryNames(source);
}
protected Collection<String> loadFactoryNames(Class<?> source) {
List<String> factoryNames = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(source, getBeanClassLoader()));
ImportCandidates.load(source, getBeanClassLoader()).forEach(factoryNames::add);
return factoryNames;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
loadFactoryNames会通过类似SPI的机制,使用classloader在classpath中查找META-INF/spring.factories
文件,在文件中寻找
配置,比如mybatis-spring-boot-autoconfigure jar包中的META-INFO/spring.factories
文件中就包含了两个自定义的AutoConfiguration类名配置
classloader会在classpath下各个jar包中以及文件夹下去查找META-INF/spring.factories
文件,不同jar包下的文件都会读出来
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
2
3
4
在从META-INF-INF/spring.factories中读取完成后,会继续读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件
这里面包含了spring-boot-autoconfigure自带的AutoConfiguration类,
其中部分内容如下,比如有AopAutoConfiguration、JdbcRepositoriesAutoConfiguration等。
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
查找好AutoConfiguration类后,在ConfigurationClassPostProcessor中执行到postProcessBeanDefinitions会解析这些AutoConfiguration类。
AutoConfiguration类的特点是大多按照条件判断是否注册对应的Configuration Bean,比如对于MybatisAutoConfiguration类,条件是有mybatis的相关依赖类的时候再自动开启。 所以会使用@ConditionalOnClass、@ConditionalOnBean、@ConditionalOnMissingClass、@ConditionalOnMissingBean等注解来控制条件。
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
}
2
3
4
5
6
7
ConfigurationClassPostProcessor会在postProcessBeanDefinitionRegistry中通过 ConfigurationClassParser解析这些AutoConfiguration类。 解析中会通过conditionEvaluator.shouldSkip判断条件是否满足,不满足跳过,满足会注册Configuration的BeanDefinition到BeanFactory中。 由此就实现了spring boot自动配置功能。
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
2
3
4
5