Where does application configuration belong in modern Java EE applications? What best practice(s) recommendations do people have?
By application configuration, I mean settings like connectivity settings to services on other boxes, including external ones (e.g. Twitter and our internal Cassandra servers...for things such as hostnames, credentials, retry attempts) as well as those relating business logic (things that one might be tempted to store as constants in classes, e.g. days for something to expire, etc).
Assumptions:
Does configuration belong inside or outside of an EAR?
If outside of an EAR, where and how best to reliably access them?
If inside of an EAR we can store it anywhere in the classpath to ease access during execution. But we'd have to re-assemble (and maybe re-build) with each configuration change. And since we'll have multiple environments, we'd need a means to differentiate the files within the EAR. I see two options here:
cassandra.properties
) and then build multiple environment specific EARs (eg. appxyz-PROD.ear
).appxyz.ear
) and put all of our various environment configuration files inside it, appending an environment variable to each config file name (eg cassandra-PROD.properties
). And of course adding an environment variable (to the vm or otherwise), so that the code will know which file to pickup.What are the best practices people can recommend for solving this common challenge?
Thanks.
I don't know what is best practice, but here is what we do.
(Note however that this only works well for one installation per application per server and will fail when one wants to use multiple deployments per server, say for multitenancy deployments).
We use a somewhat sophisticated CDI injection approach to inject configuration values from .properties
files directly into beans, like this:
@Inject @ConfigurationValue(value="amazonS3FileContentsAccessKey")
private String accessKey;
The corresponding @Producer
bean reads configuration files from the class path and from a given "local" location:
.properties
files.properties
file on the class path for configuration values that change seldom and/or usually remain consistent through environments (such as days for something to expire). Further, the global configuration file contains sane default values (e.g. "localhost
" for database server hostname). The global properties
files (there are multiple, see below) are maintained in the source tree.The expected path to "local" properties files is configured in the global configuration file (e.g., /etc/myapp/local.properties
) or C:\myapp\local.properties
.
Actually, we even allow substitution of some variables in the filename for the local configuration files, such as "${hostname}
". The original idea was that the local properties could also be maintained in some central source control by distinguishing them by hostname (local.machineA.properties
, local.machineB.properties
), but we don't use that at the moment, because our production settings are the same on all machines (Amazon S3 keys, database password/host etc).
We assemble different EARs depending on the stage of development using Maven profiles.
On assemply, the desired global.${profile.name}.properties
file (where profile.name
is, e.g., dev
or production
) is copied to the expected global.properties
file in the classpath.
For example, dev
and testing
share a common AmazonS3 secret/bucket, which is configured once for all developers in the configuration.dev.properties
file, while the configuration.production.properties
does not contain our production keys.
Furthermore, our dev
and testing
environments have debugging enabled and configured in, say web.xml
, but of course staging
and production
have not. Our .properties
-based approach cannot change files such as web.xml
, but with Maven build profiles it's easy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With