shell本节将深入介绍 Spring Boot 在这里,您可以了解您可以使用或定制的关键特征。如果你还没有准备好,你可能需要阅读 “getting-started.html” 和 “using-spring-boot.html” 为章节打下良好的基础。
1. SpringApplication
SpringApplication
从 main()
方法启动的 Spring 应用程序。在许多情况下,您可以委托静态 SpringApplication.run
就像下面的例子一样:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args); }
当您的应用程序启动时,您应该看到以下输出:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: v2.2.7.RELEASE 2019-04-31 13:09:54.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb) 2019-04-31 13:09:54.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy 2019-04-01 13:09:56.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080 2019-04-01 13:09:57.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)
默认情况下会打印 INFO
级别的日志信息,包括一些关于启动的详细信息,比如开启应用的用户,也可以修改日志级别,具体可以查看 [Log Levels](./Log Levels.md)。应用版本由主程序类包的具体版本决定。 spring.main.log.startup-info
设为 false
关闭日志信息,该操作还将关闭应用程序中确定模式下的日志信息。
你可以重写
SpringApplication
子类的logStartupInfo(boolean)
添加额外的启动日志。
1.1 Startup Failure
如果您的应用程序启动失败,则注册 FailureAnalyzers
这个问题的具体操作将提供相应的错误信息和修复。例如,如果你在 8080 启动一个端口 web 但是这个端口已经被使用了,你会看到以下类似的信息:
*************************** APPLICATION FAILED TO START *************************** Description: Embedded servlet container failed to start. Port 8080 was already in use. Action: Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Spring Boot 提供了很多
FailureAnlyzer
而且你可以实现自己。
如果没有解决问题的错误分析,你也可以显示报告中的所有信息来更好地理解错误。为了实现这个小锅,你需要 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启动 debug 属性或启动 debug 日志级别。
例如,如果你使用它 java -jar
来运行你的应用,你能像下面这样开启 debug 属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2 Lazy Initialization
SpringApplication
懒加载允许应用程序的初始化,当懒加载打开时,bean 它们将在需要时创建,而不是在应用程序打开时创建。开启懒加载可以减少应用程序的启动时间 web 在应用程序中,懒加载会导致很多 web 相关的 bean 在接受之前,它不会初始化 HTTP 请求。
懒惰加载的一个缺点是,如果一个没有配置,它会导致应用中问题的杯子延迟 bean 懒惰加载,这个错误可能不会在开始时显示,直到该 bean 被加载才会暴露出来。还必须确保 JVM 所有应用程序都有足够的内存 bean,而不仅仅是开始 bean。基于上述原因,默认情况下未打开懒加载初始化,建议在打开懒加载前打开 JVM 调整堆大小。
编程方法可用于编程 SpringApplicationBuilder
的 lazyInitation
方法或 SpringApplication
的 setLazyInitation
此外,该方法还可以使用以下内容 spring.main.lazy-initation
属性开启:
spring.main.lazy-initialization=true
如果你禁用一些应用程序,如果你禁用的话 bean 懒加载可用于剩余的开启懒加载
@Lazy(false)
注解显式地将它们的懒加载设置为 false。1.3 Customizing the Banner
banner 是在启动时输出的样式,可以通过在类路径下创建 banner.txt 文件或者设置
spring.banner.location
属性的文件路径来修改它,如果文件不是 UTF-8 编码的,你可以设置spring.banner.charset
。除了文本文件,你也可以在类路径下添加 banner.gif、banner.jpg 或 banner.png 图片文件或者设置spring.banner.image.location
属性。图片会被转换为 ASCII 形式并打印为文本 banner。在
banner.txt
中,你能使用下面的占位符:
变量 描述 ${application.version}
你应用的版本号,就像在 MANIFEST.MF 中声明的。例如 Implementation-Version: 1.0
会输出1.0
。${application.formatted-version}
你应用的版本号,就像在 MANIFEST.MF 中声明的并格式化表示(用圆括号括起来,并加上前缀 v
)。例如(v1.0)
。${spring-boot.version}
你使用的 Spring Boot 版本号,比如 2.2.7.RELEASE
。${spring-boot.formatted-version}
你使用的 Spring Boot 版本号,格式化输出(用圆括号括起来,并加上前缀 v
)。比如(v2.2.7.RELEASE)
。${Ansi.NAME}
(or${AnsiColor.NAME}
,${AnsiBackground.NAME}
,${AnsiStyle.NAME}
)NAME
是 ANSI 转义码的满足,具体查看 AnsiPropertySource。${application.title}
你应用中的主题,想 MANIFEST.MF
中声明的一样。比如Implementation-Title: MyApp
输出MyApp
。如果你想编程式创建一个 banner,可以使用
SpringApplication.setBanner(...)
方法。使用org.springframework.boot.Banner
接口并实现你自己的printBanner()
方法。你可以使用
spring.main.banner-mode
属性来确认是否将 banner 打印在System.out
(console
)、发送到指定的日志(log
)、或者不输出(off
)。banner 被注册为一个名字为
springBanner
的单例 bean。1.4 Customizing SpringApplication
如果
SpringApplication
默认的构造不符合你的要求,你可以创建一个本地实例并自定义它。比如,你可以通过这样来关闭 banner:public static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }
传给
SpringApplication
的参数是 Spring bean 的配置源。在大多数新情况下,它们都是@Configuration
类的引用,不过它们也可以是对 XML 配置的引用或者是被扫描的包的引用。可以使用
application.properties
文件对SpringApplication
进行配置,详情可查看 Externalized Configuration。查看
SpringApplication
Java 文档 获取配置的选项。1.5 Fluent Builder API
如果你想构建一个层级
ApplicationContext
(父/子 关系的多个上下文)或者你想使用链式 API 进行构建,你可以通过SpringApplicationBuilder
实现。
SpringApplicationBuilder
可以将多个方法链式调用,并且包括parent
和child
方法来创建层次结构,正如下面例子所示:new SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .bannerMode(Banner.Mode.OFF) .run(args);
创建层次
ApplicationContext
存在一些限制,比如 web 组件必须被包含在子上下文中,并且父子上下文的Environment
必须一样,具体的可以查看 SpringApplicationbuilder Java 文档 获取信息。1.6 Application Events and Listeners
除了常见的 Spring Framework 事件,比如
ContextRefreshedEvent
,SpringApplication
会发送一些附加的应用事件。有些事件是在
ApplicationContext
被创建前触发的,所以你不能将监听器使用@Bean
进行注册,你可以使用SpringApplication.addLlisterners(...)
方法或SpringApplicationBuilder.listerners(...)
方法进行注册。如果你想要监听器自动注册在应用上,无论应用是否被创建。你可以在你的项目下创建一个
META-INF/spring.factories
文件并使用org.springframework.context.ApplicationListener
键引用你的监听器,如下面所示:org.springframework.context.ApplicationListener=com.example.project.MyListener
当应用运行时,应用事件按以下的顺序派送:
ApplicationStartingEvent
在运行开始时,任何处理之前派送,除了注册监听器和初始化器之外。ApplicationEnvironmentPreparedEvent
在已知Envirment
之后,未创建上下文之前派送。ApplicationContextInitializedEvent
在ApplicationContext
准备好,ApplicationContextInitializers 被调用,但是所有 bean 定义没有被加载的时候派送。ApplicationPreparedEvent
在 refresh 之前,bean 定义被加载之后派送。ApplicationStartedEvent
在上下文被刷新之后,调用应用程序和命令行运行之前派送。ApplicationReadyEvent
在调用任意应用程序和命令行运行程序之后派送,它表示应用程序已准备好为请求提供服务。ApplicationFailedEvent
在程序出现异常时派送。上面的列表只包括绑定到
SpringApplication
的SpringApplicationEvents
。除此之外,还将在ApplicationPreparedEvent
之后和ApplicationStartedEvent
之前发布以下事件:
ContextRefreshedEvent
在ApplicationContext
被刷新的时候派送。WebServerInitializedEvent
在WebServer
准备好后派送。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是servlet
和reactive
变体。你通常不需要使用应用事件,但是了解它们对于程序处理很有帮助,在内部,Spring Boot 通过事件来处理各种任务。
应用事件通过使用 Spring Framework 的事件发布机制派送。此机制的一部分确保在子上下文中发布给监听器的事件也在任何父上下文中发布给监听器。因此,如果应用程序使用
SpringApplication
实例的层次结构,则监听器可能会接收同一类型应用程序事件的多个实例。为了让监听器区分其上下文事件和子上下文事件,它应该注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。上下文可以通过实现
ApplicationContextAware
注入,如果监听器是 bean,则可以使用@Autowired
注入。1.7 Web Environment
SpringApplication
根据你的代码尝试创建正确类型的ApplicationContext
,用于确定WebApplicationType
的算法很简单:
- 如果 Spring MVC 存在,就使用
AnnotationConfigServletWebServerApplicationContext
。- 如果 Spring MVC 不存在,Spring WebFlux 存在,就使用
AnnotationConfigReactiveWebServerApplicationContext
。- 否则使用
AnnotationConfigApplicationContext
。以上意味着如果你在同一个应用中使用了 Spring MVC 并从 Spring WebFlux 创建了
WebClient
,默认使用 Spring MVC。你可以通过调用setWebApplicationType(WebApplicationType)
来轻松覆盖它。也可以通过调用
setApplicationContextClass(...)
来完全控制ApplicationContext
类型。当在 JUnit 测试中使用
SpringApplication
时,经常需要调用setWebApplicationType(WebApplicationType.NONE)
。1.8 Accessing Application Arguments
如果你想访问传入
SpringApplication.run(...)
的应用参数,你可以注入org.springframework.boot.ApplicationArguments
bean,ApplicationArguments
接口提供对访问原始字符串数组String[]
参数以及解析的option
和no-option
参数,如下面所示:import org.springframework.boot.*; import org.springframework.beans.factory.annotation.*; import org.springframework.stereotype.*; @Component public class MyBean { @Autowired public MyBean(ApplicationArguments args) { boolean debug = args.containsOption("debug"); List<String> files = args.getNonOptionArgs(); // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"] } }
Spring Boot 还向 Spring
Envirment
注册了CommandLinePropertySource
。这还允许使用@Value
注解注入单个应用程序参数。1.9 Using the ApplicationRunner or CommandLineRunner
如果你需要在
SpringApplication
启动的时候运行一些代码,你可以实现ApplicationRunnner
或CommandLineRunner
接口,这两个接口都以相同的方式工作,并提供一个单独的run
方法,在SpringApplication.run(...)
完成前调用。
CommandLineRunner
接口简单的字符串数组形式提供对应用程序参数的访问,而ApplicationRunner
使用前面讨论的ApplicationArguments
接口。以下示例显示了带有run
方法的CommandLineRunner
:import org.springframework.boot.*; import org.springframework.stereotype.*; @Component public class MyBean implements CommandLineRunner { public void run(String... args) { // Do something... } }
如果定义了一些必须按特定顺序调用的
CommandLineRunner
或ApplicationRunner
bean,则可以另外实现org.springframework.core.Ordered
接口或使用org.springframework.core.annotation.order
注解。1.10 Application Exit
每个
SpringApplication
都向 JVM 注册一个关闭钩子函数,以确保ApplicationContext
在退出时正常关闭。可以使用所有标准的Spring
生命周期回调(例如DisposableBean
接口或@PreDestroy
注释)。此外,如果 bean 希望在调用
SpringApplication.exit()
时返回特定的退出代码,则可以实现org.springframework.boot.ExitCodeGenerator
接口。然后,可以将此退出代码传递给System.exit()
以将其作为状态代码返回,如下例所示:@SpringBootApplication public class ExitCodeApplication { @Bean public ExitCodeGenerator exitCodeGenerator() { return () -> 42; } public static void main(String[] args) { System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args))); } }
此外,
ExitCodeGenerator
接口可以通过异常实现。当遇到异常时,Spring Boot 返回由实现的getExitCode()
方法提供的退出代码。1.11 Admin Features
通过指定
spring.application.admin.enable
属性的值可以开启应用汇总有关管理的功能,这将在平台MBeanServer
上展示 SpringApplicationAdminMXBean。你可以使用这些管理特性来远程管理你的应用,这个特性对于任何服务包装器实现都很有用。如果你想知道应用运行的端口,可以获取
local.server.port
的值来查看。2. Externalized Configuration
Spring Boot 允许在外部进行配置,以便在不同的环境中使用相同的应用程序代码。你可以使用 properties 文件、YAML 文件、环境变量和命令行参数来进行外部配置。属性值可以通过使用
@Value
直接注入到bean中,可以通过 SpringEnvironment
抽象,也可以通过@ConfigurationProperties
绑定到结构化对象。Spring Boot 使用一个非常特殊的
PropertySource
顺序,它被设计为允许对值进行合理的重写。属性按以下顺序设置:
- home目录下的devtools全局设置属性(~/.spring-boot-devtools.properties,如果devtools激活)。
- 测试中的
@TestPropertySource
注解。- 测试中的属性,在
@SpringBootTest
和测试注解中提供,用于测试应用程序的特定部分。- 命令行参数。
- 来自
SPRING_APPLICATION_JSON
(内嵌在环境变量或系统属性中的 JSON)的属性。ServletConfig
初始化参数。ServletContext
初始化参数。- 来自
java:comp/env
的 JNDI 属性。- Java 系统属性(
System.getProperties()
)。- 操作系统环境变量。
RandomValuePropertySource
,其属性仅为random.*
。- jar 包之外特定于概要文件(Profile-specific application properties)的应用程序属性(
application-{Profile}.properties
和YAML
变量)。- jar 包中的特定于概要文件(Profile-specific application properties)的应用程序属性(
application-{Profile}.properties
和YAML
变量)。- jar 包之外的应用程序属性(
application.properties
和YAML
变体)。- jar 包中的应用程序属性(
application.properties
和YAML
变体)。@Configuration
类上的@PropertySource
注释。注意,在刷新应用程序上下文之前,这些属性源不会添加到环境中。此时配置某些属性(如logging.*
和spring.main.*
等)太迟了,这些属性在刷新开始之前就会被读取。- 默认属性(通过设置
SpringApplication.setDefaultProperties
指定)。为了提供一个具体的示例,假设你开发了一个使用
name
属性的@Component
,如下例所示:import org.springframework.stereotype.*; import org.springframework.beans.factory.annotation.*; @Component public class MyBean { @Value("${name}") private String name; // ... }
在应用的类路径(例如,在 jar )上,可以有一个
application.properties
文件,该文件为每个name
提供合理的默认属性值。当运行在一个新环境中,可以在 jar 外部提供application.properties
文件覆盖原文件。对于一次性的测试,可以使用特定的命令行开关进行启动启动(例如,java-jar app.jar--name="Spring"
)。
SPRING)APPLICATION_JSON
属性的值能在带有环境参数的命令行上提供,比如,你可以在 UN*X shell 上使用以下:$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar
在前面的例子中,你最后在 Spring Environment 中使用
acme.name=test
。还可以将在系统属性中将 JSON 作为spring.application.json
提供,如下例所示:$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
还可以使用命令行参数提供 JSON,如下例所示:
$ java -jar myapp.jar --spring.application.json='{"name":"test"}'
还可以将 JSON 作为 JNDI 变量提供,如下所示:
java:comp/env/spring.application.json
。2.1 Configuring Random Values
RandomValuePropertySource
对于注入随机值(例如,在机密或测试用例中)非常有用。它可以生成整数、long、uuid 或字符串,如下例所示:my.secret=${random.value} my.number=${random.int} my.bignumber=${random.long} my.uuid=${random.uuid} my.number.less.than.ten=${random.int(10)} my.number.in.range=${random.int[1024,65536]}
random.int*
的语法是OPEN value (,max) CLOSE
,OPEN, CLOSE
是任意字符,value, max
是数字。如果提供了max
,那么value
是最小值,max
是最大值(独占)。2.2 Accessing Command Line Properties
默认情况下,
SpringApplication
将任意命令行选项参数(以--
开头的参数,比如--server.port=9000
)转换为property
并且将它们添加到 SpringEnvironment
。如前所述,命令行属性始终优先于其他属性源。如果你不想让命令行属性添加到
Environment
,你可以使用SpringApplication.setAddCommandLineProperties(false)
关闭。2.2 Application Property Files
SpringApplication
从application.properties
文件加载属性。属性文件位于以下位置,并将其添加到 SpringEnvironment
中:
- 当前目录的
/config
子目录- 当前目录
- 类路径的
/config
包- 类路径的根目录下
该列表按优先级排序(在列表中较高位置定义的属性覆盖在较低位置定义的属性)。
你也可以使用 YAML(’.yml’) 文件 代替 ‘.properties’。
如果你不喜欢将
application.properties
作为配置文件名,可以通过指定spring.config.name
环境属性切换为另一个文件名。还可以使用spring.config.location
环境属性(目录位置或文件路径的逗号分隔列表)显示指定位置。以下示例演示如何指定其他文件名:$ java -jar myproject.jar --spring.config.name=myproject
下面的例子展示了如何指定两个位置:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
spring.config.name
和spring.config.location
很早就用于确定必须加载哪些文件。它们必须定义为环境属性(通常是 OS 环境变量、系统属性或命令行参数)。如果
spring.config.location
包含目录(而不是文件),则它们应该以/
(并且,在运行时,在加载之前,应该附加从spring.config.name
生成的名称,包括 profile-specific 文件的文件名)。在spring.config.location
中指定的文件按原样使用,不支持 profile-specific 变量,并且由任何特定于 profile-specific 的属性重写。配置的位置以相反的顺序搜索。默认情况下,配置的位置是
classpath:/
,classpath:/config/
,file:./
,file:./config/
。搜索结果如下:
file:./config/
file:./
classpath:/config/
classpath:/
当使用
spring.config.location
配置自定义配置位置时,它们将替换默认位置。例如,如果使用值classpath:/custom config/,file:./custom-config/
配置spring.config.location
,则搜索顺序如下:
file:./custom-config/
classpath:custom-config/
此外,当使用
spring.config.additional-location
配置自定义配置位置时,除了默认位置之外,还将使用它们。在默认位置之前搜索其他位置。例如,如果配置了classpath:/custom config/、file:./custom-config/
的其他位置,则搜索顺序如下:
file:./custom-config/
classpath:custom-config/
file:./config/
file:./
classpath:/config/
classpath:/
此搜索顺序允许你在一个配置文件中指定默认值,然后有选择地重写另一个配置文件中的这些值。你可以在默认位置之一的
application.properties
(或使用spring.config.name
选择的任何其他基本名称)中为应用程序提供默认值。然后,可以在运行时使用位于其中一个自定义位置的其他文件覆盖这些默认值。如果使用环境变量而不是系统属性,大多数操作系统不允许使用句点分隔的键名,但是可以使用下划线(例如,使用
SPRING_CONFIG_NAME
而不是SPRING.CONFIG.NAME
)。有关详细信息,参见 环境变量绑定。如果应用程序在容器中运行,那么可以使用 JNDI 属性(在
java:comp/env
中)或 servlet 上下文初始化参数来代替环境变量或系统属性,或者也可以使用环境变量或系统属性。2.4 Profile-specific Properties
除了
application.properties
文件,profile-specific 属性也能通过命名惯例application-{profile}.properties
定义。Environment
有个默认 profiles 集合(默认情况为[default]
),在没有设置激活的 profiles 时会被使用(例如,如果没有明确指定激活的 profiles,application-default.properties
中的属性会被加载)。Profile-specific 属性加载路径和标准的
application.properties
相同,并且 profile-specific 文件总是会覆盖 non-specific 文件,不管 profile-specific 文件是否被打包到 jar 中。如果定义多个 profiles,使用的是最后一个。例如,
spring.profiles.active
定义的 profiles 被添加到通过SpringApplication
API 定义的 profiles 后面,因此优先级更高。如果你已经在
spring.config.location
下定义所有文件(非目录),那些profile-specific
的文件将不被考虑。如果想使用profile-specific
属性,那就在spring.config.location
下使用目录。2.5 Placeholders in Properties
application.properties
中的值在使用时通过现有环境进行查找,因此你可以引用以前定义的值(例如,从系统属性)。app.name=MyApp app.description=${app.name} is a Spring Boot application
你可以使用此技术创建现有 Spring Boot 属性的 “短” 变体。有关详细信息,参阅 how to.html。
2.6 Encrypting Properties
Spring Boot不提供任何内置的对加密属性值的支持,但是,它提供了修改 Spring 环境中包含的值所必需的挂接点。
EnvironmentPostProcessor
接口允许在应用程序启动之前操作环境。有关详细信息,参见 howto.html。如果你正在寻找一种安全的方式来存储凭据和密码,Spring Cloud Vault 项目将为在 HashiCorp Vault 中存储外部化配置提供支持。
2.7 Using YAML Instead of Properties
YAML 是 JSON 的超集,因此,它是一种用于指定分层配置数据的方便格式。只要类路径上有
SnakeYAML
库,SpringApplication
类就会自动支持YAML
作为属性的替代。如果你使用 “Starters”,
spring-boot-starter
将自动提供 SnakeYAML 。2.7.1 Loading YAML
Spring Framework 提供了两个转换类用于加载 YAML 文档,
YamlPropertiesFactoryBean
将 YAML 加载为Properties
,YamlMapFactoryBean
将 YAML 加载为Map
。比如,思考以下 YAML 文档:
environments: dev: url: https://dev.example.com name: Developer Setup prod: url: https://another.example.com name: My Cool App
前面的示例将转换为以下属性:
environments.dev.url=https://dev.example.com environments.dev.name=Developer Setup environments.prod.url=https://another.example.com environments.prod.name=My Cool App
YAML 列表用
[index]
解引用程序表示为属性键。例如,考虑以下 YAML:my: servers: - dev.example.com - another.example.com The preceding example would be transformed
前面示例转为以下属性:
my.servers[0]=dev.example.com my.servers[1]=another.example.com
要通过使用 Spring Boot 的
Binder
实用程序(这就是@ConfigurationProperties
所做的)绑定到类似的属性,需要在目标 bean 中具有java.util.List
(或Set
)类型的属性,并且需要提供 setter 或使用可变值初始化它。例如,以下示例绑定到前面显示的属性:@ConfigurationProperties(prefix="my") public class Config { private List<String> servers = new ArrayList<String>(); public List<String> getServers() { return this.servers; } }
2.7.2 Exposing YAML as Properties in the Spring Environment
YamlPropertySourceLoader
类可用于在 SpringEnvironment
中将 YAML 暴露为 PropertySource。这样做可以使用@Value
注释和占位符语法来访问 YAML 属性。2.7.3 Multi-profile YAML Documents
你可以通过
spring.profiles
键指定文档何时应用,可以在单个文件中指定多个特定于配置文件的 YAML 文档,如下例所示:server: address: 192.168.1.100 --- spring: profiles: development server: address: 127.0.0.1 --- spring: profiles: production & eu-central server: address: 192.168.1.120
在前面的示例中,如果
development
配置处于启动状态,则server.address
属性为127.0.0.1
。类似地,如果production
和eu-central
配置处于启动状态,则server.address
属性为192.168.1.120
。如果未启用development
、production
和eu-central
配置,则属性值为192.168.1.100
。因此,
spring.profiles
可以包含一个简单的 profile 名(例如production
)或 profile 表达式。profile 表达式允许表达更复杂的 profile 逻辑,例如production&(eu-central | eu west)
。查看 参考指南 了解更多详细信息。如果应用程序上下文启动时没有显式激活配置,则将激活默认配置。因此,在下面的 YAML 中,我们为
spring.security.user.password
设置了一个仅在 “default” 配置文件中可用的值:server: port: 8000 --- spring: profiles: default security: user: password: weak
但是,在下面的示例中,密码将始终被设置好了,因为它没有附加到任何配置文件,并且必须在所有其他配置文件中根据需要显式重置密码:
server: port: 8000 spring: security: user: password: weak
使用
spring.profiles
元素指定的 Spring 配置文件可以通过使用!
字符设置否定配置文件。如果为单个文档同时指定了否定配置文件和非否定配置文件,则必须至少有一个非否定配置文件匹配,并且不能有否定配置文件匹配。2.7.4 YAML Shortcomings
YAML文件不能使用
@PropertySource
注解加载。因此,如果需要以这种方式加载值,则需要使用属性文件。在 profile-specific YAML文件中使用多个 YAML文档语法可能会导致意外行为。例如,考虑文件中的以下配置:
server: port: 8000 --- spring: profiles: "!test" security: user: password: "secret"
如果你使用参数
spring.profiles.active=dev
运行应用程序,你可能希望security.user.password
设置为 “secret”,但事实并非如此。因为主文件名为 application-dev.yml。它已经被认为是 profile-specific,因此嵌套文档将被忽略。
建议不要混合使用 profile-specific YAML文件和多个 YAML 文档。坚持只使用其中一个。
2.8 Type-safe Configuration Properties
使用
@Value()${property})
注解注入配置属性有时会很麻烦,特别是在处理多个属性或数据本质上是分层的情况下。Spring Boot 提供了另一种处理属性的方法,这种方法允许强类型 bean 控制和验证应用程序的配置。参见
@Value和类型安全配置属性之间的区别
。2.8.1 JavaBean properties binding
可以绑定一个标准 JavaBean 属性的 bean,如下面的例子所示:
package com.example; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("acme") public class AcmeProperties { private boolean enabled; private InetAddress remoteAddress; private final Security security = new Security(); public boolean isEnabled() { ... } public void setEnabled(boolean enabled) { ... } public InetAddress getRemoteAddress() { ... } public void setRemoteAddress(InetAddress remoteAddress) { ... } public Security getSecurity() { ... } public static class Security { private String username; private String password; private List<String> roles = new ArrayList<>(Collections.singleton("USER")); public String getUsername() { ... } public void setUsername(String username) { ... } public String getPassword() { ... } public void setPassword(String password) { ... } public List<String> getRoles() { ... } public void setRoles(List<String> roles) { ... } } }
前面的 POJO 定义了以下属性:
acme.enabled
,默认值为 false。
acme.remote-address
,其类型可以从字符串强制转换。
acme.security.username
,具有嵌套的 “secu