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