Spring 的环境抽象提供了对可配置的 属性源(PropertySource )层次结构的搜索操作。考虑一下下面的列表:

    1. ApplicationContext ctx = new GenericApplicationContext();
    2. Environment env = ctx.getEnvironment();
    3. boolean containsMyProperty = env.containsProperty("my-property");
    4. System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);

    在前面的片段中,我们看到了一种询问 Spring 是否为当前环境定义了 my-property 属性的高级方式。为了回答这个问题,环境对象对一组 PropertySource 对象进行了搜索。PropertySource 是对任何键值对来源的简单抽象,Spring 的 StandardEnvironment 配置了两个 PropertySource 对象,一个代表 JVM 系统属性集(System.getProperties()),另一个代表系统环境变量集(System.getenv())。

    :::info 这些默认的属性源是为 StandardEnvironment 存在的,用于独立的应用程序中。StandardServletEnvironment 被填充了额外的默认属性源,包括 servlet config 和 servlet context 参数。它可以选择性地启用一个 JndiPropertySource。详见 javadoc。 :::

    具体来说,当你使用 StandardEnvironment 时,如果运行时存在 my-property 系统属性或 my-property 环境变量,调用 env.containsProperty("my-property")会返回 true。

    :::tips 执行的搜索是分层次的。默认情况下,系统属性比环境变量有优先权。因此,如果在调用env.getProperty("my-property")时,my-property 属性恰好在两个地方都被设置了,那么系统属性值 「胜出」并被返回。请注意,属性值不会被合并,而是被前面的条目完全覆盖。

    对于一个普通的 StandardServletEnvironment 来说,完整的层次结构如下,优先级最高的条目在顶部:

    1. ServletConfig 参数(如果适用 - 例如,在 DispatcherServlet context 的情况下)。
    2. ServletContext 参数(Web.xml context-param)
    3. JNDI 环境变量(java:comp/env/
    4. JVM 系统属性 (-D 命令行参数)
    5. JVM 系统环境(操作系统环境变量) :::

    最重要的是,整个机制是可配置的。也许你有一个自定义的属性源,你想集成到这个搜索中。要做到这一点,实现并实例化你自己的 PropertySource,并将其添加到当前环境的 PropertySources 集合中。下面的例子展示了如何做到这一点:

    1. ConfigurableApplicationContext ctx = new GenericApplicationContext();
    2. MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
    3. sources.addFirst(new MyPropertySource());

    在前面的代码中,MyPropertySource 在搜索中被加入了最高优先级。如果它包含一个 my-property 属性,该属性将被检测并返回,而不是任何其他 PropertySource 中的任何 my-property 属性。MutablePropertySources API 暴露了许多方法,允许精确地操纵属性源的集合。