# 24.外化配置

Spring Boot允许将配置外部化（externalize），这样你就能够在不同的环境下使用相同的代码。你可以使用properties文件，YAML文件，环境变量和命令行参数来外部化配置。使用@Value注解，可以直接将属性值注入到beans中，然后通过Spring的`Environment`抽象或通过`@ConfigurationProperties`[绑定到结构化对象](https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-external-config-typesafe-configuration-properties)来访问。

Spring Boot设计了一个非常特别的`PropertySource`顺序，以允许对属性值进行合理的覆盖，属性会以如下的顺序进行设值：

1. home目录下的[devtools全局设置属性](http://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#using-boot-devtools-globalsettings)（`~/.spring-boot-devtools.properties`，如果devtools激活）。
2. 测试用例上的[@TestPropertySource](https://docs.spring.io/spring/docs/5.0.4.RELEASE/javadoc-api/org/springframework/test/context/TestPropertySource.html)注解。
3. 测试用例上的[@SpringBootTest#properties](http://docs.spring.io/spring-boot/docs/2.0.0.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应用属性](http://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-external-config-profile-specific-properties)（`application-{profile}.properties`和YAML变量）。
13. 打进jar包中的[Profile-specific应用属性](http://docs.spring.io/spring-boot/docs/2.0.0.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`注解](https://docs.spring.io/spring/docs/5.0.4.RELEASE/javadoc-api/org/springframework/context/annotation/PropertySource.html)。
17. 默认属性（通过设置`SpringApplication.setDefaultProperties`指定）。

下面是具体的示例，假设你开发一个使用name属性的`@Component`：

```java
import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*

@Component
public class MyBean {
    @Value("${name}")
    private String name;
    // ...
}
```

你可以将一个`application.properties`放到应用的classpath下，为`name`提供一个合适的默认属性值。当在新的环境中运行时，可以在jar包外提供一个`application.properties`覆盖`name`属性。对于一次性的测试，你可以使用特定的命令行开关启动应用（比如，`java -jar app.jar --name="Spring"`）。

**注** `SPRING_APPLICATION_JSON`属性可以通过命令行的环境变量设置，例如，在一个UNIX shell中可以这样：

```
$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar
```

在之前的例子里，如果是Spring `Environment`，你可以以`acme.name=test`结尾；如果在一个系统属性中，可以提供作为`spring.application.json`的JSON字符串：

```
$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
```

或命令行参数：

```
$ java -jar myapp.jar --spring.application.json='{"name":"test"}'
```

或作为一个JNDI变量`java:comp/env/spring.application.json`。
