views:

1399

answers:

13

You might have a set of properties that is used on the developer machine, which varies from developer to developer, another set for a staging environment, and yet another for the production environment.

In a Spring application you may also have beans that you want to load in a local environment but not in a production environment, and vice versa.

How do you handle this? Do you use separate files, ant/maven resource filtering or other approaches?

A: 

I use Ant's copy with a filter file. In the directory with the config file with variables I have a directory with a file for each environment. The build script know the env and uses the correct variable file.

Aaron
+2  A: 

I just use different Spring XML configuration files for each machine, and make sure that all the bits of configuration data that vary between machines is referenced by beans that load from those Spring configuration files.

For example, I have a webapp that connects to a Java RMI interface of another app. My app gets the address of this other app's RMI interface via a bean that's configured in the Spring XML config file. Both my app and the other app have dev, test, and production instances, so I have three configuration files for my app -- one that corresponds to the configuration appropriate for the production instance, one for the test instance, and one for the dev instance.

Then, the only thing that I need to keep straight is which configuration file gets deployed to which machine. So far, I haven't had any problems with the strategy of creating Ant tasks that handle copying the correct configuration file into place before generating my WAR file; thus, in the above example, I have three Ant tasks, one that generates the production WAR, one that generates the dev WAR, and one that generates the test WAR. All three tasks handle copying the right config file into the right place, and then call the same next step, which is compiling the app and creating the WAR.

Hope this makes some sense...

delfuego
Makes sense, and it's very similiar to what I am doing. One ant task for stage and one for production, and just using the defaults for local development. But pain arises from mainting 3 different applicationcontexts which have almost identical content..
stian
Most (all?) of the Spring ApplicationContext subclasses take an array of locations for XML configuration files, so that you can have one file for the constant information, and separate files for the variable information, and pass more than one into the constructor of each context. Does this help?
delfuego
+1  A: 

Separate configuration files, stored in the source control repository and updated by hand. Typically configuration does not change radically between one version and the next so synchronization (even by hand) isn't really a major issue.

For highly scalable systems in production environments I would seriously recommend a scheme in which configuration files are kept in templates, and as part of the build script these templates are used to render "final" configuration files (all environments should use the same process).

Tomer Gabel
I like the "template" approach, but it breaks when you're not using ant/maven and just running the app with the default from the IDE, or?
stian
I'd second the recommendation for templates, also useful if you have a single application you deploy for multiple different production deployments.I built a templateing system using ant, velocity, and VPP.
Kief
I believe it's possible to accomplish this templating approach with maven's resource filtering?
stian
How about using Spring placeholders instead of templates and during deployment renaming the host-specific config file to the included filename.
ddimitrov
A: 

I have different configuration folders holding the configurations for the target deployment, and I use ANT to select the one to use during the file copy stage.

JeeBee
+2  A: 

We use properties files specific to the environments and have the ant build select the correct set when building the jars/wars.

Environment specific things can also be handled through the directory service (JNDI), depending on your app server. We use tomcat and our DataSource is defined in Tomcat's read only JNDI implementation. Spring makes the lookup very easy.

We also use the ant strategy for building different sites (differeing content, security roles, etc) from the same source project as well.

There is one thing that causes us a little trouble with this build strategy, and that is that often files and directories don't exist until the build is run, so it can make it difficult to write true integration tests (using the same spring set up as when deployed) that are runnable from within the IDE. You also miss out on some of the IDE's ability to check for the existence of files, etc.

Caleb Phillips
+5  A: 

I just put the various properties in JNDI. This way each of the servers can be configured and I can have ONE war file. If the list of properties is large, then I'll host the properties (or XML) files on another server. I'll use JNDI to specify the URL of the file to use.

If you are creating different app files (war/ear) for each environment, then you aren't deploying the same war/ear that you are testing.

In one of my apps, we use several REST services. I just put the root url in JNDI. Then in each environment, the server can be configured to communicate with the proper REST service for that environment.

willCode4Beer
A: 

We use different ant targets for different environments. The way we do it may be a bit inelegant but it works. We will just tell certain ant targets to filter out different resource files (which is how you could exclude certain beans from being loaded), load different database properties, and load different seed data into the database. We don't really have an ant 'expert' running around but we're able to run our builds with different configurations from a single command.

zmf
A: 

One solution I have seen used is to configure the staging environment so that it is identical to the production environment. This means each environment has a VLAN with the same IP range, and machine roles on the same IP addresses (e.g. the db cluster IP is always 192.168.1.101 in each environment). The firewalls mapped external facing addresses to the web servers, so by swapping host files on your PC the same URL could be used - http://www.myapp.com/webapp/file.jsp would go to either staging or production, depending on which hosts file you had swapped in.

I'm not sure this is an ideal solution, it's quite fiddly to maintain, but it's an interesting one to note.

Kief
Interesting. But you might have listeners or services that you don't want to run in a staging environment and they would run nevertheless with this approach, right?
stian
A: 

Caleb P and JeeBee probably have your fastest solution. Plus you don't have to setup different services or point to files on different machines. You can specify your environment either by using a ${user.name} variable or by specifying the profile in a -D argument for Ant or Maven.

Additionally in this setup, you can have a generic properties file, and overriding properties files for the specific environments. Both Ant and Maven support these capabilities.

Spencer K
+1  A: 

I use Maven to filter out the resources under src/main/resources in my project. I use this in combination with property files to pull in customized attributes in my Spring-based projects.

For default builds, I have a properties file in my home directory that Maven then uses as overrides (so things like my local Tomcat install are found correctly). Test server and production server are my other profiles. A simple -Pproduction is all it then takes to build an application for my production server.

enricopulatzo
A: 

Don't forget to investigate PropertyPlaceholderConfigurer - this is especially useful in environments where JNDI is not available

belugabob
+1  A: 

I recently also used Maven for alternative configurations for live or staging environments. Production configuration using Maven Profiles. Hope it helps.

+1  A: 

Use different properties files and use ant replace filters which will do the replacement based on environment for which the build is done. See http://www.devrecipes.com/2009/08/14/environment-specific-configuration-for-java-applications/