Spring 引导:如何在 Linux ENV .profile 上使用破折号“-”覆盖属性?

Spring Boot: How to override properties with dash "-" on Linux ENV .profile?

我想用 ENV 设置覆盖 application.properties 中的任何 属性。在我的应用程序中,我使用 "prefix" 和点“.”来定义属性。和后缀 "dash"(例如“-”)。

例如:

application.server.jgroups-port= some port #

现在,我想从 OS ENV 设置中覆盖此 属性。

在 Windows 上,当我设置此 ENV 属性 时,这是我的结果:

第一(失败),

Windows ENV >> APPLICATION_SERVER_JGROUPS_PORT = 5445

environment.getProperty("application.server.jgroups-port") returns NULL

第二(失败),

Windows ENV >> APPLICATION_SERVER_JGROUPSPORT = 5445

environment.getProperty("application.server.jgroups-port") returns NULL

第三(这行得通!),

Windows ENV >> APPLICATION_SERVER_JGROUPS-PORT = 5445

environment.getProperty("application.server.jgroups-port") returns 5445

注意,最后一个"dash"(例如“-”)

耶!我已经使用 "dash" 从 Windows ENV 有效地设置了 属性。 Spring 引导将此 ENV 完美映射到应用程序 属性。

然而,在 Linux 上,它在其 ENV 中不接受 "dash"(例如,“-”),所以当我使用与我使用的相同方法时,我的 .profile 崩溃了在 Windows >> APPLICATION_SERVER_JGROUPS-PORT = 5445。我需要做什么才能使 Linux ENV 设置设置我的 "application.server.jgroups-port" 属性?

编辑: 看起来 org.springframework.core.env.SystemEnvironmentPropertySource 是我需要做一些工作来支持 Java 中的虚线 属性 名称作为 Linux ENV 的地方。例如,在 SystemEnvironmentPropertySource 中调用 getProperty("somePrefix.foo-suffix") = APPLICATION_SERVER_JGROUPS_PORT 就像它有一个句点 - getProperty("somePrefix.foo.suffix")

不能直接使用,但可以使用env程序。查看此回复 https://unix.stackexchange.com/a/23714

这是我解决问题的方法。

  1. 我分类了,SystemEnvironmentPropertySource.java。
  2. 我覆盖了 getProperty(name) 并复制了父项的 'resolvePropertyName()' 代码来进行修复。它是私有的,所以我不能只覆盖 'resolvePropertyName()',这样会更容易。
  3. 请参阅下面的 resolvePropertyName() 代码段。
  4. 我创建了一个 ApplicationListener 并将其注册到我的 Spring 启动应用程序中,以将此自定义 PropertySource 添加到 MutablePropertySources 的标准列表中。

这是变化的核心。我认为 Spring 应该在未来的版本中添加此功能。

    private String resolvePropertyName(String name) {
        Assert.notNull(name, "Property name must not be null");
        if (containsKey(name)) {
            return name;
        }

        String usName = name.replace('.', '_');
        if (!name.equals(usName) && containsKey(usName)) {
            return usName;
        }

        String ucName = name.toUpperCase();
        if (!name.equals(ucName)) {
            if (containsKey(ucName)) {
                return ucName;
            }
            else {
                String usUcName = ucName.replace('.', '_');
                if (!ucName.equals(usUcName) && containsKey(usUcName)) {
                    return usUcName;
                }

                // Jan. 27, 2015 - Jason
                // Added this code to allow replacing a property with dashes to underscores
                String usUcDashName = usUcName.replace("-", "_");
                if (containsKey(usUcDashName)) {
                    return usUcDashName;
                }
                // end modification to support dashes
            }
        }

        return name;
    }

还有 JUnit 来展示我需要发生的事情。最后的断言是我最初打开这篇文章的内容。

@RunWith(BlockJUnit4ClassRunner.class)
public class TestDashPropertySource extends TestCase{

    @Test
    public void testConvertBashToDash() throws Exception {
        Map<String, Object> mockBashENV = new HashMap<String, Object>();

        mockBashENV.put("APP_PREFIX_FOO", "foo");
        mockBashENV.put("APP_PREFIX_BAR", "bar");
        mockBashENV.put("APP_PREFIX_FOO_BAR", "foobar");

        SystemEnvironmentDashResolvingPropertySource ps = new SystemEnvironmentDashResolvingPropertySource("my-dash-handler",mockBashENV);

        Object foo = ps.getProperty("app.prefix.foo");
        assertEquals("Did not find correct value", "foo", foo);

        Object bar = ps.getProperty("app.prefix.bar");
        assertEquals("Did not find correct value", "bar", bar);

        Object foobar1 = ps.getProperty("app.prefix.foo.bar");
        assertEquals("Did not find correct value", "foobar", foobar1);

        Object foobar2_W_Dashes = ps.getProperty("app.prefix.foo-bar");
        assertEquals("Did not find correct value", "foobar", foobar2_W_Dashes);
    }

}

您还可以提供一个名为 SPRING_APPLICATION_JSON 的环境变量,其中包含有效的 JSON。这将允许您覆盖具有特殊字符的键。例如:

export SPRING_APPLICATION_JSON='{"application.server.jgroups-port": 8080}'

这样,您还可以像这样覆盖在 yaml 中定义的数组:

foo.bar:
  - 1
  - 2
  - 3

与:

export SPRING_APPLICATION_JSON='{"foo.bar": ["4","5","6"]}'

http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config

您的第二次尝试应该可以。根据 Spring Boot Reference Documentation:

To convert a property name in the canonical-form to an environment variable name you can follow these rules:

  • Replace dots (.) with underscores (_).
  • Remove any dashes (-).
  • Convert to uppercase.

我刚刚测试了一个非常相似的用例,它对我来说效果很好