> For the complete documentation index, see [llms.txt](https://jack80342.gitbook.io/spring-boot/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jack80342.gitbook.io/spring-boot/ix.-how-to-guides/73.-spring-boot-application/73.3-customize-the-environment-or-applicationcontext-before-it-starts.md).

# 73.3 启动前自定义Environment或ApplicationContext

每个`SpringApplication`都有`ApplicationListeners`和`ApplicationContextInitializers`，用于自定义上下文（context）或环境(environment)。Spring Boot从`META-INF/spring.factories`下加载很多这样的内部使用的自定义，有很多方法可以注册其他的自定义：

* 以编程方式为每个应用注册自定义，通过在`SpringApplication`运行前调用它的`addListeners`和`addInitializers`方法来实现。
* 以声明方式为每个应用注册自定义，通过设置`context.initializer.classes`或`context.listener.classes`来实现。
* 以声明方式为所有应用注册自定义，通过添加一个`META-INF/spring.factories`并打包成一个jar文件（该应用将它作为一个库）来实现。

`SpringApplication`会给监听器（即使是在上下文被创建之前就存在的）发送一些特定的`ApplicationEvents`，然后也会注册监听`ApplicationContext`发布的事件的监听器，查看Spring Boot特性章节中的[23.5. 应用事件和监听器](https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-application-events-and-listeners)可以获取完整列表。

在应用上下文刷新前使用`EnvironmentPostProcessor`自定义`Environment`是可能的，每个实现都需要注册到`META-INF/spring.factories`：

```
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
```

可以加载任意文件并将它们添加到`环境`中。例如，下面的例子从类路径加载一个YAML配置文件：

```java
public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {

    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment,
            SpringApplication application) {
        Resource path = new ClassPathResource("com/example/myapp/config.yml");
        PropertySource<?> propertySource = loadYaml(path);
        environment.getPropertySources().addLast(propertySource);
    }

    private PropertySource<?> loadYaml(Resource path) {
        if (!path.exists()) {
            throw new IllegalArgumentException("Resource " + path + " does not exist");
        }
        try {
            return this.loader.load("custom-resource", path).get(0);
        }
        catch (IOException ex) {
            throw new IllegalStateException(
                    "Failed to load yaml configuration from " + path, ex);
        }
    }

}
```

**注** 在默认情况下，`环境`已经准备好了所有通常由Spring Boot加载的属性源。因此，可以从环境中获取文件的位置。前面的示例将`自定义资源属性源`添加到列表的末尾，以便在任何其他位置定义的键具有优先级。自定义实现可以定义另一种顺序。

**警告** 虽然在`@SpringBootApplication`上使用`@PropertySource`似乎是在`环境`中加载自定义资源的一种方便而简单的方法，但是我们不推荐使用它，因为SpringBoot在刷新`ApplicationContext`之前就准备好了`环境`。使用`@PropertySource`定义的任何键加载太迟，对自动配置没有任何影响。
