SpringBoot自动配置篇

SpringBoot自动配置篇

Tomcat是利用SPI加载META-INF\services目录下的接口对应的实现类的全限定类名;Tomcat是读取所有

而SpringBoot利用SPI机制来加载META-INF\spring.factories文件中的KEY-VALUE;而springboot并不是读取所有的配置,而是有选择性的来进行读取。

1、从启动类上的主配置开始

@SpringBootApplication
public class SpringbootDemo1Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemo1Application.class, args);
    }
}

那么点进去上面的注解

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

这个是一个合成注解,由@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan组成;

所以我们通常项目中也可以看到主配置类上,直接加上这个三个注解。而不是直接使用@SpringBootApplication

1.1、@SpringBootConfiguration

@Configuration
public @interface SpringBootConfiguration {

这个类仅仅代表的当前的启动类是一个配置类,所以我们也可以在启动类中写@Bean来声明组件。

1.2、@ComponentScan

也就是包扫描,这个在spring中就看到很多次了,这里不再来进行赘述。

1.3、@EnableAutoConfiguration

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

这个注解也是一个复合注解。那么接着来分析每个注解。

1.3.1、@AutoConfigurationPackage

自动配置包,点进去看一下这个里面的注解:

@Import({Registrar.class})
public @interface AutoConfigurationPackage {

这里用其来导入一个Registrar类,从名字上可以看到这里是注册。

应该来注册组件的,这里的注册不是单一的注册一个组件,而是批量来注册组件。怎么来进行批量注册组件的?

打上断点看下下面的:

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

打上断点看一下:

可以看到该注解加在了启动类上,在上一篇章中默认的包结构就是这样子来的。

既然说是注册,那么看到了这里的包?意味着什么?意味着要进行批量注册的就是启动器所在包下的所有的组件

但是有了唯一的一个怕是不可以,还需要结合着下面的这个注解来进行操作。

1.3.2、@Import({AutoConfigurationImportSelector.class})

导入这个类,那么看下这个类的核心方法:

    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(annotationMetadata);

那么接下来来进行一波分析:

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

那么debug进去查看:

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

继续跟进:

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

工厂加载:

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    	// 缓存命中
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                // 从这里可以看到加载器来加载META-INF/spring.factories这个目录下的
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                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[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

所以我们就可以看到是从META-INF/spring.factories这个目录下面来进行加载的。

那么对应着我们的id来看:

可以看到在这个路径下,这个spring-fatories文件是写死的。我们可以进去查看:

在这里我们可以看到这个注解@EnableAutoConfiguration需要来加载的类,也就是说我们可以通过一个注解,就可以来加载到所有的需要自动配置的类。通过计算,当前场景下一共由148-22+1=127个自动配置类。

这里也就说明了项目一旦启动,spring boot就要给容器加载所有的组件。

但是spring boot在一开始启动的时候,并不会上来就加载所有的组件。

原因,我们可以通过最原始的方式来进行查看:

@SpringBootApplication
public class SpringbootDemo1Application {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringbootDemo1Application.class, args);
        System.out.println(applicationContext.getBeanDefinitionCount());  // 141个
    }
}

但是需要注意的是这141个组件中并非都有自动配置中配置的。原因是因为META-INF/spring.factories下的自动配置是否能够真正的生效。

下面就开始来讲解按需开启自动配置

虽然说META-INF/spring.factories文件中配置了127个组件,但是spring boot并非上来就马上进行加载,而是需要根据条件来进行按需加载。

所以按需加载到底是怎么来进行操作的???

下面根据例子来进行分析一下:

首先需要在META-INF/spring.factories这个包下,随便找一个自动配置类,然后点进去,我这里点击下面这个:

@Configuration(
    proxyBeanMethods = false
)

// 如果配置文件中有这个前缀,并且名字是auto的,值是true的,那么下面的这个将会成为组件。
// 即使是没有匹配上,默认也给开始了
@ConditionalOnProperty(
    prefix = "spring.aop",
    name = {"auto"},
    havingValue = "true",
    matchIfMissing = true
)
public class AopAutoConfiguration {
    public AopAutoConfiguration() {
    }
	
    // 如果系统中没有org.aspectj.weaver.Advice这个类,那么下面的将会生效
    // 前缀是spring.aop的,默认开启这个。
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnMissingClass({"org.aspectj.weaver.Advice"})
    @ConditionalOnProperty(
        prefix = "spring.aop",
        name = {"proxy-target-class"},
        havingValue = "true",
        matchIfMissing = true
    )
    static class ClassProxyingConfiguration {
        ClassProxyingConfiguration(BeanFactory beanFactory) {
            if (beanFactory instanceof BeanDefinitionRegistry) {
                BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }

        }
    }
	
    
    // 如果有Advice这个类,那么下面这个将会生效
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Advice.class})
    static class AspectJAutoProxyingConfiguration {
        AspectJAutoProxyingConfiguration() {
        }
		
       
        @Configuration(
            proxyBeanMethods = false
        )
        @EnableAspectJAutoProxy(
            proxyTargetClass = true
        )
        @ConditionalOnProperty(
            prefix = "spring.aop",
            name = {"proxy-target-class"},
            havingValue = "true",
            matchIfMissing = true
        )
        static class CglibAutoProxyConfiguration {
            CglibAutoProxyConfiguration() {
            }
        }
		
        // 如果有spring.aop这个前缀,属性是proxy-target-class的,然后值是false的,那么下面这个类将生效
        @Configuration(
            proxyBeanMethods = false
        )
        @EnableAspectJAutoProxy(
            proxyTargetClass = false
        )
        @ConditionalOnProperty(
            prefix = "spring.aop",
            name = {"proxy-target-class"},
            havingValue = "false",
            matchIfMissing = false
        )
        static class JdkDynamicAutoProxyConfiguration {
            JdkDynamicAutoProxyConfiguration() {
            }
        }
    }
}

因为在类上的注解生效了,那么也就意味着类下面的可能会生效。但是如果类上的没有生效,即使下面的有存在着生效的组件,也是不可能被加载到容器中去的。

那么首先判断项目中是否存在着Advice这个类,在idea中搜索一下,发现是没有的。所以下面这个配置就不会生效。

    // 如果系统中没有org.aspectj.weaver.Advice这个类,那么下面的将会生效
    // 前缀是spring.aop的,默认开启这个。
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnMissingClass({"org.aspectj.weaver.Advice"})
    @ConditionalOnProperty(
        prefix = "spring.aop",
        name = {"proxy-target-class"},
        havingValue = "true",
        matchIfMissing = true
    )
    static class ClassProxyingConfiguration {
        ClassProxyingConfiguration(BeanFactory beanFactory) {
            if (beanFactory instanceof BeanDefinitionRegistry) {
                BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }

        }
    }

通过上面的分析,如果我们配置了,那么我们的想要的组件就会生效;即使是我们在开发中没有来进行配置,那么spring boot这里将会提供一个简单的组件来给我们使用。但是这个默认的组件能够满足我们的需求,那就又是另外一回事儿了。

比如说上面的jdk的动态代理。

再看一个:

@Configuration(
    proxyBeanMethods = false
)
// 如果项目中有这个类,那么执行下一步
@ConditionalOnClass({CacheManager.class})
// 如果容器中有这个类型的组件,那么将会生效。我们这里去找一个,有没有这个类型的组件
@ConditionalOnBean({CacheAspectSupport.class})
@ConditionalOnMissingBean(
    value = {CacheManager.class},
    name = {"cacheResolver"}
)
@EnableConfigurationProperties({CacheProperties.class})
@AutoConfigureAfter({CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class, HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class})
@Import({CacheAutoConfiguration.CacheConfigurationImportSelector.class, CacheAutoConfiguration.CacheManagerEntityManagerFactoryDependsOnPostProcessor.class})
public class CacheAutoConfiguration {
    public CacheAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
        return new CacheManagerCustomizers((List)customizers.orderedStream().collect(Collectors.toList()));
    }

    @Bean
    public CacheAutoConfiguration.CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
        return new CacheAutoConfiguration.CacheManagerValidator(cacheProperties, cacheManager);
    }

    static class CacheConfigurationImportSelector implements ImportSelector {
        CacheConfigurationImportSelector() {
        }

        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            CacheType[] types = CacheType.values();
            String[] imports = new String[types.length];

            for(int i = 0; i < types.length; ++i) {
                imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
            }

            return imports;
        }
    }

    static class CacheManagerValidator implements InitializingBean {
        private final CacheProperties cacheProperties;
        private final ObjectProvider<CacheManager> cacheManager;

        CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
            this.cacheProperties = cacheProperties;
            this.cacheManager = cacheManager;
        }

        public void afterPropertiesSet() {
            Assert.notNull(this.cacheManager.getIfAvailable(), () -> {
                return "No cache manager could be auto-configured, check your configuration (caching type is '" + this.cacheProperties.getType() + "')";
            });
        }
    }

    @ConditionalOnClass({LocalContainerEntityManagerFactoryBean.class})
    @ConditionalOnBean({AbstractEntityManagerFactoryBean.class})
    static class CacheManagerEntityManagerFactoryDependsOnPostProcessor extends EntityManagerFactoryDependsOnPostProcessor {
        CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
            super(new String[]{"cacheManager"});
        }
    }
}

根据上面的分析,首先去找一下有没有CacheAspectSupport这个类型的组件:

@SpringBootApplication
public class SpringbootDemo1Application {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringbootDemo1Application.class, args);

        String[] beanNamesForType = applicationContext.getBeanNamesForType(CacheAspectSupport.class);
        System.out.println(beanNamesForType.length);  // 0
    }
}

发现根本就没有这个类型的组件,那么类上的不生效,类中的@Bean当然也就不会再生效。

所以以后分析的顺序就是先看类上的注解是否是可以生效的,如果类上的没有生效,那么就没有必要再来看类下面的注解了。

那么再来看一下生效的,找一个我们当前场景下配置了mvc的web模块:

那么我们可以看到非常多的AutoConfiguration

// 加载配置顺序的
@AutoConfigureOrder(-2147483648)
@Configuration(
    proxyBeanMethods = false
)

// 是原始的servlet类型还是响应式编程
@ConditionalOnWebApplication(
    type = Type.SERVLET
)

// 项目中是否有这个类
@ConditionalOnClass({DispatcherServlet.class})

// 要在这个组件在加载之后再来进行下面的操作
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
public class DispatcherServletAutoConfiguration {

所以分析到这里,可以看到这里的类上的注解可以是成功的。

那么看一下这个包的内部类:

    @Configuration(
        proxyBeanMethods = false
    )
	// 是否有这个类
    @Conditional({DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition.class})
	// 项目中是否有这个类
    @ConditionalOnClass({ServletRegistration.class})
	// 这个就是我们之前分析的常用注解。两个功能:1、成为组件;2、让这个类的属性和配置文件中的属性进行绑定
    @EnableConfigurationProperties({WebMvcProperties.class})
	// 导入这个类,让其成为组件
    @Import({DispatcherServletAutoConfiguration.DispatcherServletConfiguration.class})
    protected static class DispatcherServletRegistrationConfiguration {
        protected DispatcherServletRegistrationConfiguration() {
        }

        @Bean(
            name = {"dispatcherServletRegistration"}
        )
        @ConditionalOnBean(
            value = {DispatcherServlet.class},
            name = {"dispatcherServlet"}
        )
        public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
            DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
            registration.setName("dispatcherServlet");
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            multipartConfig.ifAvailable(registration::setMultipartConfig);
            return registration;
        }
    }

那么看一下这个类:

@ConfigurationProperties(
    prefix = "spring.mvc"
)
public class WebMvcProperties {
    private org.springframework.validation.DefaultMessageCodesResolver.Format messageCodesResolverFormat;
    private Locale locale;
    private WebMvcProperties.LocaleResolver localeResolver;
    private final WebMvcProperties.Format format;
    private boolean dispatchTraceRequest;
    private boolean dispatchOptionsRequest;
    private boolean ignoreDefaultModelOnRedirect;
    private boolean publishRequestHandledEvents;
    private boolean throwExceptionIfNoHandlerFound;
    private boolean logRequestDetails;
    private boolean logResolvedException;
    private String staticPathPattern;
    private final WebMvcProperties.Async async;
    private final WebMvcProperties.Servlet servlet;
    private final WebMvcProperties.View view;
    private final WebMvcProperties.Contentnegotiation contentnegotiation;
    private final WebMvcProperties.Pathmatch pathmatch;

看到这里,就是再常见不过的配置类了。所有的配置都可以和配置文件中的进行绑定

那么也可以来验证一下,获取得到这个类型的组件:

@SpringBootApplication
public class SpringbootDemo1Application {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringbootDemo1Application.class, args);

        String[] beanNamesForType = applicationContext.getBeanNamesForType(WebMvcProperties.class);
        System.out.println(beanNamesForType.length);  // 1
    }
}

那么既然验证了是存在的,说明注解都成立了,再看看下面的操作:

    @Configuration(
        proxyBeanMethods = false
    )
    @Conditional({DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition.class})
    @ConditionalOnClass({ServletRegistration.class})
	// 开启了自动绑定
    @EnableConfigurationProperties({WebMvcProperties.class})
    protected static class DispatcherServletConfiguration {
        protected DispatcherServletConfiguration() {
        }

        @Bean(
            name = {"dispatcherServlet"}
        )
        // 不是我们不需要配置,而是说这里已经帮助我们配置好了
        // 加载方法上的@Bean,方法上的参数会从容器中来查找有没有这种类型的组件
        public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
            dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
            dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
            dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
            dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
            return dispatcherServlet;
        }
		
        
        // 这个也是非常常见的。如果没有这个名字的bean,这里就会生效
        // 这里就会由一个常见的习惯,文件解析器就叫这个名字,不能进行更改了。也就是说给文件上传解析器改名字了	
        // 容器有这个类型的组件,但是没有这个名字的组件。那么就将这个组件返回
        // 防止文件上传解析器命名不规范,那么就使用这个名字的文件上传解析器,因为方法名字叫做multipartResolver
        @Bean
        @ConditionalOnBean({MultipartResolver.class})
        @ConditionalOnMissingBean(
            name = {"multipartResolver"}
        )
        public MultipartResolver multipartResolver(MultipartResolver resolver) {
            return resolver;
        }
    }

那么再看一个web开发中最常见的字符编码问题,看看spring boot中是如何来进行实现的。

@Configuration(
    proxyBeanMethods = false
)
@EnableConfigurationProperties({ServerProperties.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
// 即使没有,这里也配置了
@ConditionalOnProperty(
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    private final Encoding properties;

    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }
	
    // 如果没有,那么下面的生效。如果有了,那么这里的将不会生效
    @Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
    }

    @Bean
    public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
    }

    static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
        private final Encoding properties;

        LocaleCharsetMappingsCustomizer(Encoding properties) {
            this.properties = properties;
        }

        public void customize(ConfigurableServletWebServerFactory factory) {
            if (this.properties.getMapping() != null) {
                factory.setLocaleCharsetMappings(this.properties.getMapping());
            }

        }

        public int getOrder() {
            return 0;
        }
    }
}

SpringBoot中强调的默认给配置好了,但是如果说用户自己有配,那么使用用户的。核心实现:@ConditionalOnMissingBean

有这个注解来进行达到的。这就体现出来了SpringBoot中的一个核心思想,约定大于配置。

总结一下:

  • springboot会先加载所有的配置类;
  • 每个自动配置类按照条件生效; 一旦配置生效,就会绑定上配置文件中的值,对应的值都是在XXXProperties中,而XXXProperties又是和配置文件来进行绑定的
  • 生效的配置类会给容器中配置很多组件;
  • 只要容器中有这些组件,那么这些功能就有了
  • 只要存在用户自己配置的,那么就使用用户的

定制化配置:

1、用户自己用@Bean组件来替换掉底层默认配置好的;

2、在配置文件中修改XXXProperties对应的值即可;

自动配置----------->导入组件------------>XXXProperties------->配置文件中的值

总结一下:spring boot中的配置,在启动的时候会去METAINF目录下去加载对应的自动配置,自动配置会按照条件进行自动装配,然后向容器中生成对应的组件,而组件中会有对应的属性,而组件对应的属性又绑定着application.properties或者是yaml文件中的属性

通过这个我们可以来进行修改自定义的信息

6.1、查看生效配置和没有生效的配置

在进行自动配置的时候,需要注意一点的是,如何知道我们的配置是否已经生效了?

  • 引入外界的配置一般都是生效的;
  • 自定义配置或者是加入对应的组件

如果向看到哪些配置是否已经生效了,我们可以在properties文件上加上一个

debug=true

开启自动配置报告。来测试是否我们自己引入的是否已经成功了

Positive matches:生效的配置
Negative matches:没有生效的配置

在spring boot中需要配置什么?一般如果不知道什么,那么就直接去官方文档中来进行查找即可。

官方文档对应的地址:

https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties

2、自动配置总结

posted @ 2021-10-30 17:11  雩娄的木子  阅读(657)  评论(0编辑  收藏  举报