How can I easily switch between environment specific runtime configuration with IntelliJ?

末鹿安然 提交于 2020-01-16 01:06:30

问题


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


回答1:


When I ran in similar problems, I started loading my properties with a helper class. The helper class will look for a System property that contains either the environment or the absolute/classpath-relative path to load the properties from.

That way, the code is always the same and I don't have to change the project's configuration. I just use different launch configs that set different properties.

The main drawback here of course that test / dev configs leak into prod. With Maven, the simple solution is to move those into a new module and set the scope for it to provided. That way, the module will be visible inside of Maven but it won't be included during WAR packaging, etc.




回答2:


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>


来源:https://stackoverflow.com/questions/21557545/how-can-i-easily-switch-between-environment-specific-runtime-configuration-with

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!