如何轻松地在环境特定的运行时配置与IntelliJ之间切换? [英] How can I easily switch between environment specific runtime configuration with IntelliJ?

查看:1053
本文介绍了如何轻松地在环境特定的运行时配置与IntelliJ之间切换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在大多数Java项目(Maven,Spring)我的工作,我有以下要求:




  • 包装的jar需要运行在多个环境中

  • 每个环境都需要不同的配置属性

  • 在开发中,我需要能够在不同环境之间轻松切换,以确保在部署之前正确配置每个环境。



到目前为止,我已经实现了这一点,将所有配置属性放入单独的属性文件,每个环境一个。我然后有Spring加载在这些文件从类路径。然后我只是改变类路径在运行时加载所需的属性。



这种方法在我使用Eclipse时工作得很好,因为它很容易设置多个运行配置,改变每个类的类路径。一旦这样做,切换环境是选择相关运行配置的问题。



不幸的是,这是很难在IntelliJ中完成,因为运行时依赖只能添加到模块的配置(此答案中所述)。如果我尝试在运行配置本身设置类路径,那么这将覆盖所有模块依赖,阻止应用程序运行(,如此处所述)。因此,为了切换环境,我必须每次都重新编辑模块的依赖。



有更简单的方法来实现IntelliJ?



如果不是,是因为我的配置要求,或我的解决方案,是不寻常的?



已经尝试并拒绝了许多方法:




  • Maven个人资料 - 这些都需要重新构建我的jar每当我想切换环境。除了恼人和危险,这似乎完全不适合运行时配置(但是理想的 buildtime 配置)。这似乎是一个很好的方式来冒险让破碎的构建进入生产,因为你不是测试同一个实际部署的jar。 Yuck!


  • Spring Profiles - 这些看起来更合适,但似乎需要所有配置与jar一起部署, dev.properties,prod.properties。然后,您可以通过在运行时传递变量来选择您想要的那个。这是更好的,但我不想让我的prod.properties找到他们的方式进入版本控制,也没有部署与jar本身。因此,它似乎有必要修改类路径,以便包括它我不能轻易做的IntelliJ



解决方案

我做类似于@AaronDigulla的东西,但我覆盖的属性。这是我首先从属性文件加载所有的属性在类路径(使用Spring)。然后我在servlet init参数中搜索特定的变量名和值(按以下顺序):


  1. 然后是系统属性

  2. 最后是环境变量

此变量名称和值包含将覆盖/覆盖从类路径加载的属性的属性文件的路径。此外,每个加载的属性将执行相同类型的解析(即系统属性,环境变量和servlet init参数覆盖属性文件中的属性)。



被推送以使用类路径中的默认配置(即,为其数据库使用相同的用户名/密码)。具有不同设置的用户可以使用上述3种不同的方式覆盖。



您可以使用相同的引导配置代码 ,这将加载 classpath *中的所有属性文件:META-INF / spring / .properties 首先,它将加载所有的属性文件与在属性/ environment / init参数变量中设置的文件/类路径URL MyConfigParameter 设置)。



然后最后在加载属性文件后,通过拉动属性/ environment / init参数 MyConfig来设置Spring配置文件。



因此在生产环境中你可以设置环境变量 MyConfigParameter = file:// etc / myapp / *。properties



然后在这些属性文件中,可以设置 MyConfig.profiles = production ,将设置Spring配置文件生产 postgres

$ postgres b
$ b

您的Maven配置文件在您的构建机器上发布/构建显然可以使用系统属性调整环境中的 MyConfigParameter 。但是,你必须告诉确切的单元测试专门关于这个属性(特别是如果分叉):

 < - > 
< plugin>
< groupId> org.apache.maven.plugins< / groupId>
< artifactId> maven-surefire-plugin< / artifactId>
< version> 2.9< / version>
< configuration>
< printSummary> false< / printSummary>
< redirectTestOutputToFile> true< / redirectTestOutputToFile>
< systemPropertyVariables>
< MyConfigParameter> $ {MyConfigParameter}< / MyConfigParameter>
< / systemPropertyVariables>
< / configuration>
< / plugin>

<! - 要更改MyConfigParameter的配置文件 - >

< profiles>
< profile>
< id> release< / id>
< activation>
< property>
< name> env< / name>
< value> release< / value>
< / property>
< / activation>
< properties>
< MyConfigParameter> file://etc/MyApp/*.properties< / MyConfigParameter>
< / properties>
< / profile>
< / profiles>


In most Java projects (Maven, Spring) I work on, I have the following requirements:

  • The packaged jar needs to run in multiple environments e.g. dev, beta, prod
  • The jar must not be rebuilt for each environment
  • Each environment requires different configuration properties
  • In development, I need to be able to easily switch between different environments in order to ensure that each environment is configured correctly, before deployment

So far, I have accomplished this by putting all configuration properties into separate properties files, one per environment. I then have Spring load in these files from the classpath. Then I simply alter the classpath at runtime to load in the needed properties.

This approach has worked well when I was using Eclipse since it is easy to setup multiple run configurations and alter the classpath for each one. Once this is done, switching environments is a matter of choosing the relevant run configuration.

Unfortunately, this is much harder to accomplish in IntelliJ because runtime dependencies can only be added to a module's configuration (as documented in this answer). If I try to set the classpath in the run configuration itself then this overrides all of modules dependencies, preventing the application from running at all (as documented here). Therefore, to switch environment, I must re-edit the modules dependencies every time.

Is there an easier way of achieving this with IntelliJ?

If not, is that because my configuration requirements, or my solutions to them, are unusual? In which case, is there a better way?

Previous Approaches

I have already tried and rejected a number of approaches:

  • Maven Profiles - These require rebuilding my jar whenever I want to switch environment. Apart from being annoying and dangerous, this seems entirely inappropriate for runtime configuration (but ideal for buildtime configuration). This seems like a great way to risk getting a broken build into production as you aren't testing against the same jar that actually gets deployed. Yuck!

  • Spring Profiles - These look much more appropriate but appear to require all configuration to be deployed with the jar and distinguished by filename e.g. dev.properties, prod.properties. You can then select which one you want by passing a variable at runtime. This is much better but I don't want my prod.properties to find their way into version control, nor get deployed with the jar itself. Therefore, it still seems necessary to modify the classpath in order to include them which I can't easily do in IntelliJ

解决方案

I do something similar to what @AaronDigulla does but I overlay the properties. That is I first load all the properties from property files in the classpath (using Spring). Then I search for specific variable name and value (in the following order):

  1. in servlet init parameters
  2. then in system properties
  3. finally then environment variables

This variable name and value contains the path of property files that will override/overlay the properties loaded from the classpath. Also each property loaded will perform the same type of resolution (that is system properties, environment variables and servlet init parameters override the properties from the property file).

Now all developers are pushed to use the default configuration that is in the classpath (ie use the same username/password for their database). Those that have different settings can use the above 3 different ways to override.

You can use the same bootstrapping configuration code that I use which will load all property files in classpath*:META-INF/spring/*.properties first then it will load all property files with the file/classpath URL set in the property/environment/init parameter variable called MyConfigParameter (if set).

Then finally after the property files are loaded it will set the Spring profiles by pulling the property/environment/init parameter called MyConfig.profiles (comma separated).

So in production you might set the environment variable MyConfigParameter=file://etc/myapp/*.properties.

Then in one of those property files you might set MyConfig.profiles=production,postgres which will set the Spring profile production and postgres.

Your Maven profiles for releasing/building on your build machine can obviously adjust the MyConfigParameter in the environment using System Properties. However you will have to tell surefire unit testing specifically about this property (especially if forking):

        <!-- Surefire setup -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.9</version>
            <configuration>
                <printSummary>false</printSummary>
                <redirectTestOutputToFile>true</redirectTestOutputToFile>
                <systemPropertyVariables>
                    <MyConfigParameter>${MyConfigParameter}</MyConfigParameter>
                </systemPropertyVariables>                    
            </configuration>
        </plugin>

<!-- Profile to change MyConfigParameter -->

<profiles>
    <profile>
        <id>release</id>
        <activation>
            <property>
                <name>env</name>
                <value>release</value>
            </property>
        </activation>
        <properties>
            <MyConfigParameter>file://etc/MyApp/*.properties</MyConfigParameter>
        </properties>
    </profile>
</profiles>

这篇关于如何轻松地在环境特定的运行时配置与IntelliJ之间切换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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