# 24\. 外部配置
Spring Boot允许您外部化您的配置,以便您可以在不同的环境中使用相同的应用程序代码。 您可以使用properties文件,YAML文件,环境变量和命令行参数来外部化配置。 可以使用@Value注释将属性值直接注入到您的bean中,该注释可通过Spring环境(Environment)抽象访问,或通过@ConfigurationProperties[绑定到结构化对象](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-typesafe-configuration-properties)。
Spring Boot使用非常特别的PropertySource命令,旨在允许合理地覆盖值。属性按以下顺序选择:
1. 在您的HOME目录设置的[Devtools全局属性](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#using-boot-devtools-globalsettings)(~/.spring-boot-devtools.properties)。
2. 单元测试中的 [@TestPropertySource](http://docs.spring.io/spring/docs/4.3.7.RELEASE/javadoc-api/org/springframework/test/context/TestPropertySource.html) 注解。
3. 单元测试中的 [@SpringBootTest#properties](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/api/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTest.html) 注解属性
4. 命令行参数。
5. SPRING_APPLICATION_JSON 中的属性值(内嵌JSON嵌入到环境变量或系统属性中)。
6. ServletConfig 初始化参数。
7. ServletContext 初始化参数。
8. 来自 java:comp/env 的JNDI属性。
9. Java系统属性(System.getProperties())。
10. 操作系统环境变量。
11. RandomValuePropertySource,只有随机的属性 random.* 中。
12. jar包外面的 [Profile-specific application properties](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-profile-specific-properties) (application- {profile} .properties和YAML变体)
13. jar包内的 [Profile-specific application properties](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-profile-specific-properties) (application-{profile}.properties和YAML变体)
14. jar包外的应用属性文件(application.properties和YAML变体)。
15. jar包内的应用属性文件(application.properties和YAML变体)。
16. 在@Configuration上的@PropertySource注解。
17. 默认属性(使用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来覆盖 name 属性; 对于一次性测试,您可以使用特定的命令行开关启动(例如,java -jar app.jar --name="Spring")。
SPRING_APPLICATION_JSON属性可以在命令行中提供一个环境变量。 例如在UN*X shell中:
```
$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar
```
在本例中,您将在Spring环境中使用foo.bar = spam。 您也可以在系统变量中将JSON作为spring.application.json提供:
```
$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar
```
或命令行参数:
```
$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}'
```
或作为JNDI变量 java:comp/env/spring.application.json 。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#241-配置随机值)24.1 配置随机值
RandomValuePropertySource可用于注入随机值(例如,进入秘密或测试用例)。 它可以产生整数,长整数,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](http://random.int) *语法是 OPEN value (,max) CLOSE ,其中OPEN,CLOSE是任何字符和值,max是整数。 如果提供max,则值为最小值,max为最大值(独占)。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#242-访问命令行属性)24.2 访问命令行属性
默认情况下,SpringApplication将任何命令行选项参数(以'-- '开头,例如--server.port=9000)转换为属性,并将其添加到Spring环境中。 如上所述,命令行属性始终优先于其他属性来源。
如果不希望将命令行属性添加到环境中,可以使用SpringApplication.setAddCommandLineProperties(false)禁用它们。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#243-应用程序属性文件)24.3 应用程序属性文件
SpringApplication将从以下位置的application.properties文件中加载属性,并将它们添加到Spring Environment中:
1. 当前目录的/config子目录
2. 当前目录
3. classpath中/config包
4. classpath root路径
该列表按优先级从高到低排序。
> 也可以[使用YAML('.yml')文件](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-yaml)替代“.properties”。
如果您不喜欢application.properties作为配置文件名,[可以通过指定一个spring.config.name](http://xn--spring-9m7igl21dt6y8qu0luc56kg7a.config.name/) Spring environment属性来切换到另一个。 您还可以使用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](http://spring.config.name)和spring.config.location一开始就被用于确定哪些文件必须被加载,因此必须将它们定义为环境属性(通常是OS env,system属性或命令行参数)。
如果spring.config.location包含的如果是目录而非文件,那么它们应该以/结尾(并将在加载之前附加从[spring.config.name](http://spring.config.name)生成的名称,包括profile-specific的文件名)。 在spring.config.location中指定的文件按原样使用,不支持特定于配置文件的变体,并且将被任何特定于配置文件的属性覆盖。
默认的搜索路径 classpath:,[classpath:/config,file:,file:config/](http://classpath/config,file:,file:config/) 始终会被搜索,不管spring.config.location的值如何。 该搜索路径从优先级排序从低到高(file:config/最高)。 如果您指定自己的位置,则它们优先于所有默认位置,并使用相同的从最低到最高优先级排序。 这样,您可以在application.properties(或使用[spring.config.name](http://spring.config.name)选择的任何其他基础名称)中为应用程序设置默认值,并在运行时使用不同的文件覆盖它,并保留默认值。
> 如果您使用环境(environment)变量而不是系统属性,大多数操作系统不允许使用句点分隔(period-separated)的键名称,但可以使用下划线(例如,SPRING_CONFIG_NAME,[而不是spring.config.name](http://xn--spring-vp7io16nrw9b.config.name/))
> 如果您运行在容器中,则可以使用JNDI属性(在 java:comp/env 中)或servlet上下文初始化参数,而不是环境变量或系统属性。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#244-指定配置profile-specific的属性)24.4 指定配置(Profile-specific)的属性
除了application.properties文件外,还可以使用命名约定application- {profile}.properties定义的指定配置文件。 环境具有一组默认配置文件,如果没有设置活动配置文件(即,如果没有显式激活配置文件,则加载了来自application-default.properties的属性)。
指定配置文件(Profile-specific)的属性从与标准application.properties相同的位置加载,指定配置( profile-specific)文件始终覆盖非指定文件,而不管指定配置文件是否在打包的jar内部或外部。
如果有几个指定配置文件,则应用最后一个配置。 例如,由spring.profiles.active属性指定的配置文件在通过SpringApplication API配置的配置之后添加,因此优先级高。
> 如果您在spring.config.location中指定了任何文件,则不会考虑这些特定配置(profile-specific)文件的变体。 如果您还想使用指定配置(profile-specific)文件的属性,请使用`spring.config.location`中的目录。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#245-properties-文件中的占位符)24.5 properties 文件中的占位符
application.properties中的值在使用时通过已有的环境进行过滤,以便您可以引用之前定义的值(例如,从系统属性)。
```
app.name=MyApp
app.description=${app.name} is a Spring Boot application
```
> 您也可以使用此技术创建现有Spring Boot属性的“简写“。 有关详细信息,请参见[第72.4节“使用”短命令行参数“how-to”](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#howto-use-short-command-line-arguments)。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#246-使用yaml替代-properties)24.6 使用YAML替代 Properties
[YAML](http://yaml.org/)是JSON的超集,因此这是分层配置数据一种非常方便的格式,。 每当您的类路径中都有[SnakeYAML](http://www.snakeyaml.org/)库时,SpringApplication类将自动支持YAML作为 properties 的替代方法。
> 如果您使用“Starters”,SnakeYAML将通过spring-boot-starter自动提供。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2461-加载-yaml)24.6.1 加载 YAML
Spring Framework提供了两个方便的类,可用于加载YAML文档。 `YamlPropertiesFactoryBean`将YAML作为`Properties`加载,`YamlMapFactoryBean`将YAML作为Map加载。
例如,下面YAML文档:
```
environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App
```
将转化为属性:
```
environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App
```
YAML列表表示为具有[index] dereferencers的属性键,例如YAML:
```
my:
servers:
- dev.bar.com
- foo.bar.com
```
将转化为属性:
```
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com
```
要使用Spring DataBinder工具(@ConfigurationProperties做的)绑定到这样的属性,您需要有一个属性类型为java.util.List(或Set)的目标bean,并且您需要提供一个setter,或者 用可变值初始化它,例如 这将绑定到上面的属性
```
@ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
}
}
```
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2462-将yaml作为spring环境中的属性文件)24.6.2 将YAML作为Spring环境中的属性文件
可以使用YamlPropertySourceLoader类在Spring环境中将YAML作为PropertySource暴露出来。 这允许您使用熟悉的@Value注解和占位符语法来访问YAML属性。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2463-多个yaml文件)24.6.3 多个YAML文件
您可以使用`spring.profiles`键指定单个文件中的多个特定配置文件YAML文档,以指示文档何时应用。 例如:
```
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production
server:
address: 192.168.1.120
```
在上面的示例中,如果开发配置文件处于活动状态,则server.address属性将为127.0.0.1。 如果开发和生产配置文件未启用,则该属性的值将为192.168.1.100。
如果应用程序上下文启动时没有显式激活,默认配置文件将被激活。 所以在这个YAML中,我们为security.user.password设置一个仅在“默认”配置文件中可用的值:
```
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
```
使用“spring.profiles”元素指定的Spring profiles 以选择使用`!` 字符。 如果为单个文档指定了否定和非否定的配置文件,则至少有一个非否定配置文件必须匹配,没有否定配置文件可能匹配。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2464-yaml的缺点)24.6.4 YAML的缺点
YAML文件无法通过@PropertySource注解加载。 因此,在需要以这种方式加载值的情况下,需要使用properties文件。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2465-合并yaml列表)24.6.5 合并YAML列表
[如上所述](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-loading-yaml),任何YAML内容最终都会转换为属性。 当通过配置文件覆盖“列表”属性时,该过程可能比较直观。
例如,假设名称和描述属性默认为空的MyPojo对象。 让我们从FooProperties中公开MyPojo的列表:
```
@ConfigurationProperties("foo")
public class FooProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
```
类比以下配置:
```
foo:
list:
- name: my name
description: my description
---
spring:
profiles: dev
foo:
list:
- name: my another name
```
如果dev配置没有激活,FooProperties.list将包含一个如上定义的MyPojo条目。 如果启用了配置文件,列表仍将包含一个条目(名称为“my another name”,description=null)。 此配置不会将第二个MyPojo实例添加到列表中,并且不会将项目合并。
当在多个配置文件中指定集合时,使用具有最高优先级的集合(并且仅使用该配置文件):
```
foo:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
foo:
list:
- name: my another name
```
在上面的示例中,考虑到dev配置文件处于激活状态,FooProperties.list将包含一个MyPojo条目(名称为“my another name”和description=null)。
### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#247-类型安全的配置属性)24.7 类型安全的配置属性
使用@Value(“${property}”)注释来注入配置属性有时可能很麻烦,特别是如果您正在使用多个层次结构的属性或数据时。 Spring Boot提供了一种处理属性的替代方法,允许强类型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("foo")
public class FooProperties {
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定义了以下属性:
* foo.enabled,默认为false
* foo.remote-address,具有可以从String强转的类型
* foo.security.username,具有内置的“安全性(security)”,其名称由属性名称决定。 特别是返回类型并没有被使用,可能是SecurityProperties
* foo.security.password
* foo.security.roles,一个String集合
Getters和setter方法通常是必须要有的,因为绑定是通过标准的Java Beans属性描述符,就像在Spring MVC中一样。 在某些情况下可能会省略setter方法:
* Map 只要它们被初始化,需要一个getter,但不一定是一个setter,因为它们可以被binder修改。
* 集合和数组可以通过索引(通常使用YAML)或使用单个逗号分隔值(Properties中)来访问。 在后一种情况下,setter方法是强制性的。 我们建议总是为这样的类型添加一个设置器。 如果您初始化集合,请确保它不是不可变的(如上例所示)
* 如果已初始化嵌套POJO属性(如上例中的Security字段),则不需要setter方法。如果您希望binder使用其默认构造函数即时创建实例,则需要一个setter。
有些人使用Project Lombok自动添加getter和setter。 确保Lombok不会为这种类型生成任何特定的构造函数,因为构造函将被容器自动用于实例化对象。
> 另请参阅[@Value和@ConfigurationProperties之间的不同](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-vs-value)。
您还需要列出在`@EnableConfigurationProperties`注解中注册的属性类:
```
@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}
```
> 当`@ConfigurationProperties` bean以这种方式注册时,该bean将具有常规名称:`<prefix> - <fqn>`,其中<prefix>是@ConfigurationProperties注解中指定的环境密钥前缀,<fqn>是bean的全名(fully qualified name)。 如果注解不提供任何前缀,则仅使用该bean的全名。上面示例中的bean名称将是foo-com.example.FooProperties。
即使上述配置将为FooProperties创建一个常规bean,我们建议@ConfigurationProperties仅处理环境,特别是不从上下文中注入其他bean。 话虽如此,@EnableConfigurationProperties注释也会自动应用于您的项目,以便使用@ConfigurationProperties注释的任何现有的bean都将从环境配置。 您可以通过确保FooProperties已经是一个bean来快速上面的MyConfiguration
```
@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {
// ... see above
}
```
这种配置方式与SpringApplication外部的YAML配置相当:
```
# application.yml
foo:
remote-address: 192.168.1.1
security:
username: foo
roles:
- USER
- ADMIN
# additional configuration as required
```
要使用@ConfigurationProperties bean,您可以像其他任何bean一样注入它们。
```
@Service
public class MyService {
private final FooProperties properties;
@Autowired
public MyService(FooProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}
}
```
> 使用@ConfigurationProperties还可以生成IDE可以为自己的密钥提供自动完成的元数据文件,有关详细信息,请参见[附录B,配置元数据附录](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#configuration-metadata)。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2471第三方配置)24.7.1第三方配置
除了使用@ConfigurationProperties来注解类,还可以在public @Bean方法中使用它。 当您希望将属性绑定到不受控制的第三方组件时,这可能特别有用。
```
@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
...
}
```
使用 bar 前缀定义的任何属性将以与上述FooProperties示例类似的方式映射到该BarComponent bean。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2472-宽松的绑定)24.7.2 宽松的绑定
Spring Boot使用一些宽松的规则将环境属性绑定到@ConfigurationProperties bean,因此不需要在Environment属性名称和bean属性名称之间进行完全匹配。 常用的例子是这样有用的:虚分离(例如上下文路径绑定到contextPath)和大写(例如PORT绑定到端口)环境属性。
例如,给定以下@ConfigurationProperties类:
```
@ConfigurationProperties(prefix="person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
```
可以使用以下属性名称:
表格 24.1\. relaxed binding
| Property | Note |
| --- | --- |
| person.firstName | 标准骆峰命名法。 |
| person.first-name | 虚线符号,推荐用于.properties和.yml文件。 |
| person.first_name | 下划线符号,用于.properties和.yml文件的替代格式。 |
| PERSON_FIRST_NAME | 大写格式 推荐使用系统环境变量时。 |
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2473属性转换)24.7.3属性转换
当Spring绑定到@ConfigurationProperties bean时,Spring将尝试将外部应用程序属性强制为正确的类型。 如果需要自定义类型转换,您可以提供ConversionService bean(使用bean id conversionService)或自定义属性编辑器(通过CustomEditorConfigurer bean)或自定义转换器(使用注释为@ConfigurationPropertiesBinding的bean定义)。
> 由于在应用程序生命周期期间非常早请求此Bean,请确保限制ConversionService正在使用的依赖关系。 通常,您需要的任何依赖关系可能无法在创建时完全初始化。 如果配置密钥强制不需要,只需依赖使用@ConfigurationPropertiesBinding限定的自定义转换器,就可以重命名自定义ConversionService。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2474-configurationproperties验证)24.7.4 @ConfigurationProperties验证
当Spring的@Validated注释解时,Spring Boot将尝试验证@ConfigurationProperties类。 您可以直接在配置类上使用JSR-303 javax.validation约束注释。 只需确保您的类路径中符合JSR-303实现,然后在您的字段中添加约束注释:
```
@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
```
为了验证嵌套属性的值,您必须将关联字段注释为@Valid以触发其验证。 例如,基于上述FooProperties示例:
```
@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// ... getters and setters
public static class Security {
@NotEmpty
public String username;
// ... getters and setters
}
}
```
您还可以通过创建名为configurationPropertiesValidator的bean定义来添加自定义的Spring Validator。 @Bean方法应声明为static。 配置属性验证器在应用程序的生命周期早期创建,并声明@Bean方法,因为static允许创建bean,而无需实例化@Configuration类。 这避免了早期实例化可能引起的任何问题。 这里有一个[属性验证的例子](https://github.com/spring-projects/spring-boot/tree/v1.5.2.RELEASE/spring-boot-samples/spring-boot-sample-property-validation),所以你可以看到如何设置。
> `spring-boot-actuator`模块包括一个暴露所有@ConfigurationProperties bean的端点。 只需将您的Web浏览器指向/configprops 或使用等效的JMX端点。 请参阅[生产就绪功能](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#production-ready-endpoints) 细节。
#### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2475-configurationproperties-对比-value)24.7.5 @ConfigurationProperties 对比 @Value
@Value是核心容器功能,它不提供与类型安全配置属性相同的功能。 下表总结了@ConfigurationProperties和@Value支持的功能:
| 功能 | @ConfigurationProperties | @Value |
| --- | --- | --- |
| Relaxed binding | Yes | No |
| Meta-data support | Yes | No |
| SpEL evaluation | No | Yes |
如果您为自己的组件定义了一组配置密钥,我们建议您将其分组到使用@ConfigurationProperties注释的POJO中。 还请注意,由于@Value不支持宽松的绑定,如果您需要使用环境变量提供值,那么它不是一个很好的选择。
最后,当您可以在@Value中编写一个Spel表达式时,这些表达式不会从[应用程序属性文件](http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-application-property-files)中处理。
- Part I. Spring Boot 文档
- Part II. 入门指南
- 8. Spring Boot 介绍
- 9. 系统要求
- 10. 安装 Spring Boot
- 11. 开发您的第一个Spring Boot应用程序
- 12. 接下来应该读什么
- Part III. 使用 Spring Boot
- 13. 构建系统
- 14. 构建代码
- 15. 配置类
- 16. 自动配置
- 17. Spring Beans 和 依赖注入
- 18. 使用@SpringBootApplication注解
- 19. 运行你的应用程序
- 20. 开发工具
- 21. 包装您的应用程序到生产环境
- 22. 接下来应该读什么
- Part IV. Spring Boot 功能
- 23. SpringApplication
- 24. 外部配置
- 25. 配置文件(Profiles)
- 26. 日志
- 27. 开发Web应用程序
- 28. Security
- 29. 使用SQL数据库