在Spring中添加新属性源的最佳方法是什么?

时间:2015-11-14 23:14:25

标签: spring configuration

我想添加一个可用于读取应用程序中属性值的新属性源。我想用Spring做这件事。我在@Configuration类中有一段这样的代码:

@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {        
    PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
    MutablePropertySources sources = new MutablePropertySources();
    MyCustomPropertySource propertySource = new MyCustomPropertySource("my custom property source");
    sources.addFirst(propertySource);
    properties.setPropertySources(sources);
    return properties;
}

这看起来效果很好。但是,它还在做的是覆盖其他属性值(例如spring boot使用的application.properties文件中的server.port属性),我不想覆盖它们。所以基本的问题是添加此属性源的最佳方法是什么,但不要覆盖其他属性。有没有什么方法可以获取现有的属性资源并简单地添加它?

5 个答案:

答案 0 :(得分:1)

您可能尝试的一件事是将IgnoreUnresolvablePlaceholders设置为TRUE。我有一个类似的问题,我能够以这种方式解决。在我的情况下,我有另一个占位符配置器,它正在工作 - 但第二个中的属性没有被解析,除非我将此属性设置为TRUE。

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {        
    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
    propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
    propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(Boolean.TRUE);
    return propertySourcesPlaceholderConfigurer;
}

答案 1 :(得分:1)

我通过在Spring Boot应用程序中添加一个自定义的启动器来实现这一目的:

@SpringBootApplication
public class MyApp {

    public static void main(String[] args) {
        new SpringApplicationBuilder(VftApp.class)
            .initializers(new MyContextInitializer())  // <---- here
            .run(args);
    }

}

MyContextInitializer包含:-

public class MyContextInitializer implements
    ApplicationContextInitializer<ConfigurableApplicationContext> {

    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();

        // Create map for properites and add first (important)
        Map<String, Object> myProperties = new HashMap<>();
        myProperties.put("some-prop", "custom-value");
        environment.getPropertySources().addFirst(
            new MapPropertySource("my-props", myProperties));
    }

}

请注意,如果您的application.yaml包含:-

some-prop: some-value
another-prop: this is ${some-prop} property

然后,initialize方法会将some-prop更新为custom-value,并在应用加载时在运行时具有以下值:

some-prop: custom-value
another-prop: this is custom-value property

请注意,如果initialize方法进行了简单的System.setProperty调用,即

    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        System.setProperty("some-prop", "custom-value");
    }

...然后another-prop等于this is some-value property,这不是我们通常想要的(并且我们失去了Spring config属性解析的能力)。

答案 2 :(得分:0)

您可以在初始化后将propertySource直接添加到环境中。

编辑:由于这是在处理完类之后完成的,因此您不能指望@Value注释从同一@Configuration类中的此特定PropertySource中获取任何内容 - 或之前加载的任何其他内容。

@Configuration
public class YourPropertyConfigClass{

    @Value("${fromCustomSource}")
    String prop; // failing - property source not yet existing

    @Autowired
    ConfigurableEnvironment env;

    @PostConstruct
    public void init() throws Exception {
        env.getPropertySources().addFirst(
             new MyCustomPropertySource("my custom property source"));
    }
}

@Configuration
@DependsOn("YourPropertyConfigClass")
public class PropertyUser {

    @Value("${fromCustomSource}")
    String prop; // not failing
}

您可以将@PostConstruct移动到单独的@Configuration类,并使用这些属性标记其他类@DependOn("YourPropertyConfigClass")(这有效 - 但也许有更好的方法来强制配置顺序?)

无论如何 - 只有使用MyCustomPropertySource注释无法简单地添加@PropertySource("file.properties"),这是值得的 - 这将解决简单属性文件的问题。

答案 3 :(得分:0)

如果您实现PropertySourceFactory:

import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;

public class CustomPropertySourceFactory implements PropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) {
        ...
    }
}

您可以使用以下属性来源:

@PropertySource(name="custom-prop-source", value="", factory=CustomPropertySourceFactory.class)

有点hack-ish,但它确实有效。

答案 4 :(得分:0)

另一种可能性(经过大量实验,这对我有用)是在PropertySource中声明您的ApplicationContextInitializer,然后将其注入您的SpringBootServletInitializer

public class MyPropertyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    private static final Logger logger = LoggerFactory.getLogger(ApplicationPropertyInitializer.class);

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        MyPropertySource ps = new MyPropertySource();
        applicationContext.getEnvironment().getPropertySources().addFirst(ps);
    }

}
public class MyInitializer extends SpringBootServletInitializer{

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return super.configure(builder.initializers(new MyPropertyInitializer()));
    }

}