SpringBoot------自动配置原理再理解、debug=true(八)

自动配置原理再理解

配置文件到底能写哪些东西

从注解一步一步看
@SpringBootApplication–>
@EnableAutoConfiguration(自动导入配置)–>
@Import({AutoConfigurationImportSelector.class})
自动配置导入选择器
.selectImports()方法获取候选配置。

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

this.getAutoConfigurationEntry方法
获得所有的实体

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    
    
        if (!this.isEnabled(annotationMetadata)) {
    
    
            return EMPTY_ENTRY;
        } else {
    
    
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

this.getCandidateConfigurations
获取候选的配置

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    
    
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

this.getSpringFactoriesLoaderFactoryClass()
获取标注了EnableAutoConfiguration注解的所有类

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    
    
        return EnableAutoConfiguration.class;
    }

SpringFactoriesLoader.loadFactoryNames加载配置

 public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    
    
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
    
    
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

loadSpringFactories(classLoaderToUse)
遍历META-INF/spring.factories文件下的所有url

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    
    
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
    
    
            return result;
        } else {
    
    
            HashMap result = new HashMap();

            try {
    
    
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
    
    
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
    
    
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
    
    
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
    
    
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

spring.factories是核心的自动装配文件,SpringBoot的所有配置都在其中配置好了,每一个xxxxAutoConfiguration都是容器中的一个组件,但并不是所有组件都生效了。
META-INF/spring.factories
application.yaml文件中能写的配置都在spring.factories文件中,当然yaml文件中还能够自定义spring.factories文件中没有的配置。

举例:

org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,能够按着ctrl点进去看内容。
在这里插入图片描述
@Configuration:表示这是一个配置类。
@EnableConfigurationProperties:自动配置属性,能够指定配置哪一个类,点击ServerProperties,看看它的具体内容。
可以看到HttpEncodingAutoConfiguration的构造函数就传入了ServerProperties类。
@ConditionalOnWebApplication:是Spring的底层注解,根据不同的条件,来判断当前配置或者类是否生效。此处只有type = Type.SERVLET时,该配置类才会生效。
在这里插入图片描述
可以再ServerProperties 类中看到有@ConfigurationProperties注解。这个注解在之前自己手动创建类,并在配置文件中配置属性时已经用到。
@ConfigurationProperties:代表这个类能够在配置文件中对它的属性进行手动配置。

@ConfigurationProperties(
    prefix = "server",
    ignoreUnknownFields = true
)
public class ServerProperties {
    
    
    private Integer port;
    private InetAddress address;
    @NestedConfigurationProperty

在这里插入图片描述
@Conditional扩展注解
在这里插入图片描述

在配置文件中能配置的东西,都存在一个固有的规律 ,一定会存在xxxProperties类,这个类会被大量的xxxAutoConfiguration装配,xxxProperties类有默认值。并且xxxProperties类 和 配置文件绑定,xxxProperties类的属性修改,就在配置文件中进行自定义。

精髓

1.SpringBoot启动会加载大量的自动配置类
2.我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类中;
3.我们再来看这个自动配置类中到底配置了那些组件;(只要我们要用的组件存在其中,我们就不需要再手动配置)
4.给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可。
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性,SpringBoot配置文件就是用来修改这些属性。

debug = true

在yaml文件中配置debug: true,就能够在控制台打印出那些自动配置类生效、那些自动配置类没有生效,进行查看。
生效示例:

Positive matches:
-----------------

   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

未生效示例:

Negative matches:
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

排斥的示例:

Exclusions:
-----------

    None

没有条件的示例:

Unconditional classes:
----------------------

    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration

    org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration

    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

这些未自动装配的配置,如果需要配置,只需要导入对应的Start即可。

Guess you like

Origin blog.csdn.net/cz_chen_zhuo/article/details/117033414