目录
71.3 Customize the Environment or ApplicationContext before it starts
官网文档
71.3 Customize the Environment or ApplicationContext before it starts
A
SpringApplication
hasApplicationListeners
andApplicationContextInitializers
that are used to apply customizations to the context or environment. Spring Boot loads a number of such customizations for use internally fromMETA-INF/spring.factories
. There is more than one way to register additional ones:
- Programmatically per application by calling the
addListeners
andaddInitializers
methods onSpringApplication
before you run it.- Declaratively per application by setting
context.initializer.classes
orcontext.listener.classes
.- Declaratively for all applications by adding a
META-INF/spring.factories
and packaging a jar file that the applications all use as a library.The
SpringApplication
sends some specialApplicationEvents
to the listeners (even some before the context is created), and then registers the listeners for events published by theApplicationContext
as well. See Section 23.5, “Application events and listeners” in the ‘Spring Boot features’ section for a complete list.It is also possible to customize the
Environment
before the application context is refreshed usingEnvironmentPostProcessor
. Each implementation should be registered inMETA-INF/spring.factories
:org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
The implementation can load arbitrary files and add them to the
Environment
. For instance, this example loads a YAML configuration file from the classpath: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, null); } catch (IOException ex) { throw new IllegalStateException( "Failed to load yaml configuration from " + path, ex); } } }
The
Environment
will already have been prepared with all the usual property sources that Spring Boot loads by default. It is therefore possible to get the location of the file from the environment. This example adds thecustom-resource
property source at the end of the list so that a key defined in any of the usual other locations takes precedence. A custom implementation may obviously defines another order.
While using
@PropertySource
on your@SpringBootApplication
seems convenient and easy enough to load a custom resource in theEnvironment
, we do not recommend it as Spring Boot prepares theEnvironment
before theApplicationContext
is refreshed. Any key defined via@PropertySource
will be loaded too late to have any effect on auto-configuration.
翻译
71.3 在环境或应用程序上下文启动之前对其进行自定义
SpringApplication具有ApplicationListeners和
ApplicationContextInitializers属性,
public class SpringApplication { ... private List<ApplicationContextInitializer<?>> initializers; private List<ApplicationListener<?>> listeners; ... }
用于对上下文或者环境进行自定义。SpringBoot从META-INF/Spring.Factories中加载了许多这样的定制以供内部使用。有多种方法可以注册其他方法:
通过在运行SpringApplication之前对其调用addListeners和addInitializers方法,以编程方式为每个应用程序提供支持。
通过设置context.initializer.classes或context.listener.classes声明每个应用程序。
通过添加META-INF/spring.factures并打包应用程序都用作库的JAR文件,声明性地针对所有应用程序。
SpringApplication向监听器发送一些特殊的applicationEvents(甚至在创建上下文之前发送一些),然后为applicationContext发布的事件注册监听器。有关完整列表,请参阅“Spring引导功能”部分的第23.5节“应用程序事件和侦听器”。
还可以在使用EnvironmentPostProcessor自定义环境在刷新应用程序上下文之前。每个实现都应该在META-INF/Spring.Factories中注册:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
实现可以加载任意文件并将其添加到环境中。例如,本例从类路径加载yaml配置文件:
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, null); } catch (IOException ex) { throw new IllegalStateException( "Failed to load yaml configuration from " + path, ex); } } }
环境已经准备好了所有通常的属性源,默认情况下Spring引导加载这些属性源。因此,可以从环境中获取文件的位置。此示例将自定义资源属性源添加到列表的末尾,以便在任何通常的其他位置中定义的键优先。自定义实现显然可以定义另一个顺序。
虽然在@SpringBootApplication 上使用@PropertySource似乎非常方便和容易,可以在环境中加载自定义资源,但我们不建议这样做,因为在刷新
ApplicationContext
之前,Spring boot会准备好环境。通过@PropertySource定义的任何键将被加载太晚,无法对自动配置产生任何影响。