如何将Spring配置为部分和可选地覆盖属性? [英] How do I configure Spring to partially and optionally override properties?

查看:313
本文介绍了如何将Spring配置为部分和可选地覆盖属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望有一个属性设置,可以在某些环境中覆盖特定属性。例如,我们对dev的默认JDBC属性是:

I would like to have a properties setup which can, on certain environments, override specific properties. For example, our default JDBC properties for dev are:


  • db.driverClassName = com.mysql.jdbc.Driver

  • db.url = jdbc:mysql:// localhost:3306 / ourdb

  • db.username = root

  • db.password =

  • db.driverClassName=com.mysql.jdbc.Driver
  • db.url=jdbc:mysql://localhost:3306/ourdb
  • db.username=root
  • db.password=

问题是我们的一些开发人员希望在数据库上使用不同的用户名/密码,或者甚至可能是非本地托管数据库。我们的rabbitMQ配置也是如此,它目前使用类似的localhost,guest / guest设置。能够在每个开发人员的基础上覆盖此配置的某些元素的属性将允许我们移动大部分基础架构/安装要求,以便从本地计算机和专用服务器上构建软件。

The problem is that some of our devs would like to have a different username/password on the db, or possibly even a non locally hosted db. The same is true for our rabbitMQ configuration, which currently uses a similar localhost, guest/guest setup. Being able to override the properties of certain elements of this configuration on a per-developer basis would allow us to move much of the infrastructure/installation requirements for building the software off the local machine and onto dedicated servers.

我已经设置了一个简单的项目来围绕实现我想要的配置,这是我第一次涉足Spring属性配置的世界,因为到目前为止,属性使用一些自定义代码完成加载和管理。这是我的设置:

I have set-up a simple project to wrap my head around the configuration required to achieve what I want, and this is my first foray into the world of spring property configuration, since up till now, property loading and management is done with some custom code. Here is my setup:

class Main_PropertyTest {
    public static void main(String[] args) {
        String environment = System.getenv("APPLICATION_ENVIRONMENT"); // Environment, for example: "dev"
        String subEnvironment = System.getenv("APPLICATION_SUB_ENVIRONMENT"); // Developer name, for example: "joe.bloggs"
        System.setProperty("spring.profiles.active", environment);
        System.setProperty("spring.profiles.sub", subEnvironment);

        try(AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PropertyTestConfiguration.class)) {
            Main_PropertyTest main = context.getBean(Main_PropertyTest.class);
            main.printProperty();
        }
    }

    private final String property;

    public Main_PropertyTest(String property) {
        this.property = property;
    }

    public void printProperty() {
        System.out.println("And the property is: '" + property + "'.");
    }
}

我的配置:

@Configuration
public class PropertyTestConfiguration {
    @Bean
    public static PropertySourcesPlaceholderConfigurer primaryPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(System.getProperty("spring.profiles.active") + ".main.properties"));
        return propertySourcesPlaceholderConfigurer;
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer secondaryPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(System.getProperty("spring.profiles.sub") + ".main.properties"));
        propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true);
        propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true);
        propertySourcesPlaceholderConfigurer.setOrder(-1);
        return propertySourcesPlaceholderConfigurer;
    }

    @Bean
    public Main_PropertyTest main_PropertyTest(@Value("${main.property}") String property) {
        Main_PropertyTest main_PropertyTest = new Main_PropertyTest(property);
        return main_PropertyTest;
    }
}

为了完整性,我的dev.main.properties和test.main.properties:

And for completeness, my dev.main.properties and test.main.properties:

main.property=dev

main.property=test

主要问题是我得到了非法的参数异常。据我所知,我写的应该是javaconfig相当于这个方法: http://taidevcouk.wordpress.com/2013/07/04/overriding-a-packaged-spring-application-properties-file- via-an-external-file /
不幸的是我收到以下错误:java.lang.IllegalArgumentException:无法在字符串值$ {main.property}中解析占位符'main.property'。请注意,我还需要处理没有子环境的情况,这是我已经开始的情况(尽管即使两个文件都存在,我也会得到相同的错误)。如果我删除了设置第二个propertysourcesplaceholderconfigurer的bean,那么一切正常(我的意思是加载dev.main.properties并且并且属性为:'dev'。打印出来。)

The main problem is that I get an illegal argument exception. As far as I can tell, what I have written should be the javaconfig equivalent of this method: http://taidevcouk.wordpress.com/2013/07/04/overriding-a-packaged-spring-application-properties-file-via-an-external-file/ Unfortunately I get the following error: java.lang.IllegalArgumentException: Could not resolve placeholder 'main.property' in string value "${main.property}". Note that I also need to take care of the case where there is no sub-environment, and this is the case I have started with (although I get the same error even if both files exist). If I remove the bean which sets up the second propertysourcesplaceholderconfigurer, then it all works fine (by which I mean dev.main.properties is loaded and "And the property is: 'dev'." is printed out).

第二个问题是代码看起来不太好,系统的每一层都需要两个PSPC的设置,以便他们可以访问这些属性。此外,它需要大量手动调用System.getProperty(),因为我无法将$ {spring.profiles.active}传递给PSPC.setLocation();

A secondary problem is that the code doesn't look great, and each layer of the system will need two PSPC's set-up so that they can access these properties. Furthermore, it requires a lot of manual calls to System.getProperty(), since I couldn't pass ${spring.profiles.active} to PSPC.setLocation();

注意:我尝试过@PropertySources({primaryproperties,secondaryProperties}),但由于secondaryProperties不存在而失败。我也试过@Autowired Environment环境;并从中获取属性,但辅助PSPC导致环境无法自动装配......

Note: I have tried @PropertySources({primaryproperties, secondaryProperties}), but this fails because secondaryProperties does not exist. I have also tried @Autowired Environment environment; and getting the properties from that, but the secondary PSPC causes the environment to not be autowired...

因此,经过这个冗长的解释,我的问题是:

So following this lengthy explanation, my questions are:


  • 这是解决此问题的正确方法吗?

  • 如果是,我的配置有什么问题?

  • 如何简化配置(如果有的话)?

  • 是否有可用的替代机制可以解决我的问题?

  • Is this the right way of solving this problem?
  • If so, what is wrong with my configuration?
  • How can I simplify the configuration (if at all)?
  • Is there an alternative mechanism available which would solve my problem?

感谢您的时间! :)

推荐答案

使用java配置配置 BeanFactoryPostProcessor 时,您的配置存在缺陷方法应该是静态的。然而,它可以更容易,而不是注册自己的 PropertySourcesPlaceholderConfigurer 利用默认的 @PropertySource 支持。

Your configuration is flawed when configuring BeanFactoryPostProcessor with java config the methods should be static. However it can be even easier, instead of registering your own PropertySourcesPlaceholderConfigurer utilize the default @PropertySource support.

将您的jav配置转换为以下内容

Rewerite your jav config to the following

@Configuration
@PropertySource(name="main", value= "${spring.profiles.active}.main.properties")
public class PropertyTestConfiguration {

    @Autowired
    private Environment env;

    @PostConstruct
    public void initialize() {
        String resource = env.getProperty("spring.profiles.sub") +".main.properties";
        Resource props = new ClassPathResource(resource);
        if (env instanceof ConfigurableEnvironment && props.exists()) {
            MutablePropertySources sources = ((ConfigurableEnvironment) env).getPropertySources();
            sources.addBefore("main", new ResourcePropertySource(props)); 
        }
    }

    @Bean
    public Main_PropertyTest main_PropertyTest(@Value("${main.property}") String property) {
        Main_PropertyTest main_PropertyTest = new Main_PropertyTest(property);
        return main_PropertyTest;
    }
}

这应首先加载 dev.main.properties 以及 test.main.properties ,它将覆盖先前加载的属性(当填充时)。

This should first load the dev.main.properties and additionally the test.main.properties which will override the earlier loaded properties (when filled ofcourse).

这篇关于如何将Spring配置为部分和可选地覆盖属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆