美文网首页
SpringBoot自动配置

SpringBoot自动配置

作者: 有梦想的虫子_2018 | 来源:发表于2020-09-23 18:08 被阅读0次

1、@SpringBootApplication注解

springboot启动类上都会配置@SpringBootApplication注解,用来加载配置

@SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ……
}

2、@EnableAutoConfiguration注解

我们可以看到@SpringBootApplication是组合注解,其中@EnableAutoConfiguration注解进行自动配置,加载bean到IOC容器。

@EnableAutoConfiguration

@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 {};//排除指定class
    String[] excludeName() default {};//排除指定类名

}

@EnableAutoConfiguration由两个关键注解组成@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class),下面我们分别解释下这两个注解。

3、@AutoConfigurationPackage注解

/**
 * Registers packages with {@link AutoConfigurationPackages}.
 *  When no {@link #basePackages  base packages} or {@link #basePackageClasses base package classes} are specified, the
 * package of the annotated class is registered.
* 注册在basePackages和basePackageClasses指定的class,如果没有指定那么注册
* 这个注解类修饰的类所在的包
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
}

@Import(AutoConfigurationPackages.Registrar.class)

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

    }

把启动类所在的包注册进去了


image.png

4、@Import(AutoConfigurationImportSelector.class)

自动装配的核心是扫描约定目录下的文件进行解析,解析完成之后把得到的Configuration配置类通过ImportSelector进行导入,从而完成Bean的自动装配过程。springboot由AutoConfigurationImportSelector来实现的。下面进行详细解析:


image.png

selectImports方法

@Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }

最终调用到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);
    }
  • getAttributes获得@EnableAutoConfiguration注解中的属性exclude、excludeName等
  • getCandidateConfigurations获得所有自动装配的配置类
  • removeDuplicates去除重复的配置项
  • getExclusions根据@EnableAutoConfiguration注解中的exclude、excludeName属性,把不需要自动装配的配置类移除。
  • 最后返回多层判断和过滤后的配置类集合
    总的来说,它先获取所有类的配置,通过去重、exclude排除等操作,得到最终需要实现自动装配的配置类。这里需要关注的是getCandidateConfigurations,它是获取配置类的核心方法。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                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;
    }

这里用到了SpringFactoriesLoader,它是Spring内部提供的一种约定俗成的加载方式,类似于Java中SPI(Service Provider Interface)。简单来说,它会扫描META-INF/spring.factories问价,spring.factories问价中的数据以key=value形式存储。在这个场景中,Key对应EnableAutoConfiguration,Value是多个配置类,也就是getCandidateConfigurations方法返回的值。

image.png

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
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,\

5、总结

  • 通过@Import(AutoConfigurationImportSelector.class)实现配置类的导入
  • AutoConfigurationImportSelector实现了ImportSelector接口,重写了selectImports,实现选择性批量配置了的装配。
  • 通过Spting提供的SpringFactoriesLoader机制,扫描classpath路径下的META-INF/spring.factories,读取需要实现自动装配的配置类。
  • 通过条件筛选,把不符合条件的配置类移除,最终完成自动装配。

Spring Cloud Alibaba 微服务原理与实战 ——谭锋(Mic)著

相关文章

网友评论

      本文标题:SpringBoot自动配置

      本文链接:https://www.haomeiwen.com/subject/mrsoyktx.html