美文网首页
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