# 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 {};
}
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

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 {};
}
1
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));
    }

}
1
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);
	}

1
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;
}
1
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
1
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
1

查找好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 {
}
1
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;
    }

1
2
3
4
5