Best Way to externalize system properties on a multi-environment application - spring

We are working with a Spring 3 application that runs on several environments (test, UAT and Production) these environments are managed by a third party company so we have almost no access to the servers.
We have tried with Jboss System Properties and Maven2 Profiles. Both solutions worked fine, however we don't want to tie the application to one specific Server (Jboss in this case) and we don't want to do environment specific builds (required for Maven2 profiles).
Is there a good way we could have environment specific properties for the app that do not require different builds for each environment and require no modifications on the server side and that could also run on different servers? (some sort of PropertyPlaceHolderConfigurer that could read property files outside the app context should do the trick)

Environment-specific builds are not a bad option.
But spring 3.1 is providing what you are looking for - environment specific configuration. See this and this

Related

Best approach to build and run with env specific values - Spring and K8S

Building a Spring based project deployed in kubernetes using Spring Cloud Kubernetes library with Kubernetes. The build is using maven and GIT CI/CD. Exploring the build process to package environment specific files and the runtime to pick up env specific files during execution. In traditional deployment, used to use maven profiles to build env specific libraries and configurations. Now spring has profile and maven has its profile. Besides, some of the designs includes files/configurations for all env included in the build and only a activated profile will use the correct configuration. Is it advisable to include all configurations in the package?
Is there a best approach on how these two work in handling env specific files or any other optimized approach to handle this?
I'm afraid that:
In traditional deployment, used to use maven profiles to build env specific libraries and configurations
was never a case for maven profiles, if you take a look at official guide you may find following:
Apache Maven goes to great lengths to ensure that builds are portable. Among other things, this means allowing build configuration inside the POM, avoiding all filesystem references (in inheritance, dependencies, and other places), and leaning much more heavily on the local repository to store the metadata needed to make this possible.
However, sometimes portability is not entirely possible. Under certain conditions, plugins may need to be configured with local filesystem paths. Under other circumstances, a slightly different dependency set will be required, and the project's artifact name may need to be adjusted slightly. And at still other times, you may even need to include a whole plugin in the build lifecycle depending on the detected build environment.
To address these circumstances, Maven supports build profiles.
So, maven profiles was designed to support codebase portability across build environments, but not to build artifacts for particular environment.
"Traditional" way to inject environment-specific settings into j2ee-application was to setup those settings via JNDI, i.e. j2ee-container was providing a configuration via JNDI and our application was consuming that configuration via JNDI. In case of spring/k8s/etc the main idea should remain the same: application knows how to retrieve configuration (system properties, environment variables, configuration server, service discovery, etc) and environment provides that configuration.

Switch between Prod and Dev environment

I've built a REST Service with Spring Boot. The setup in the development environment is different from the setup in the production environment. What is the best approach to switching setup between development environment and production environment? By setup I mean for instance the path to the database that is different in development vs. production. I can think of three approaches, use environment variables, use a properties file or use config file. Other suggestions are welcome and what I should think about when choosing.
You should have a look at Spring Profiles - see here. Using spring profile, u can easily switch configurations for the different environments.
Just name your configuration for "dev" as "application-dev.(properties|yaml) and provide -Dspring.profiles.active=dev when running the App from command line.

How to configure different data sources for local testing and deployment in Spring Boot Application

I am trying to find the best way to configure my Spring Boot Web application to easily switching between the following data sources for both local testing and deployment.
H2 in memory db. Local testing only.
Dev oracle. Local testing and deployment.
Prod oracle. Deployment only.
By local testing, I mean to test in IDE environment (Eclipse). Dev and prod oracle databases are set up on two remote servers.
After some research, there are different ways to switch from one data source to another.
Use Spring profile. Using H2 and Oracle with Spring Boot. Set up the following files in classpath, application.properties, application-h2. properties and application-dev.properties. While connections for h2 and dev are defined in corresponding properties files, spring.profiles.active is set in application.properties. My understanding is this property can be overridden during build process by specifying spring.profiles.active. However, it seems to be a JVM variable, how do I set it running maven?
Maven profile. Create multiple profiles in pom and a filter pointing to application properties files. The profile specified by -P option during maven build will determine which application properties file to look. However, according to maven application with multi environment configuration can't deploy on tomcat, this will generate multiple wars for different deployment. So method 1 is preferred. Plus, it does not apply to switching datasources while testing locally.
Persistence units. Define different persistence units for different data sources in persistence.xml. Use EntityManager by choosing a specific unit. Variation of this method include having a variable in unit names which is determined in application.properties.
JNDI lookup. Set up a jndi name in application.properties with spring.datasource.jndi-name. The actual database information including url and credentials will be specified in context.xml in the tomcat folder where the war will be deployed.
My mind is set on local testing environment. Gonna go with method 1. Switching between H2 in memory and oracle is so easy just by changing the property in application.properties. Since the testing is usually done in IDE, war does not need to be generated, although answers are welcome for run maven install with spring.profiles.active.
As far as deployment, JNDI is definitely the way to go. However, I am concerned that the two properties in application.properties: spring.profiles.active and spring.datasource.jndi-name may be conflicting with each other. If I have spring.profiles.active=h2 and then tried to deploy the war to prod server, does it try to connect to h2 based on the spring profile or to prod db based on jdni-name? What is the best practice to accommodate all scenarios with enough flexibility?
Also is a explicit configuration class for DataSource required such as Configure Mutiple DataSource in Spring Boot with JNDI? My understanding is application.properties and spring profile should be enough to handle it, right?
Definitely use Spring profiles.
You don't want to use Maven profiles as it creates different artifacts. Ask your QA/Release engineers how they feel about having different artifacts for different environments :). They wouldn't be happy.
H2 is what you want to use in CI server integration testing as well. Such integration testing is fast and easy.
Instead of changing profile in application.properties, consider defining profile via command line parameter. So that configuration file changes are not required to run your application in different profiles.

Spring Environment profiles and server properties

I have a requirement to load properties for different environments like DEV, QA and I have different properties file for each environment. So I solved this by setting environment property in server and accessing this value to load respective property files. When googled I found that Spring Environment Profiles provides the solution for similar scenarios. However, even here I have to set active-profile variable in server as environment variable.
What are the benefits of using Spring Environment Profiles over my native approach?
Profile lets you override anything in the Spring Context, properties, beans etc, from environment to environment, customer to customer. It is a easy and clean way to have custom implementations at any level of your beans.
For example, Lets assume your are building a product which read data from a relational database, you can develop DAO layer with profile="default". Then if another customer of yours or you yourself want to provide NoSQL support, you can develop another DAO layer with profile="nosql". This will make sure you can same product on both support based on profile. Easy and clean.
I am working on a project which have profile="local" which will help you bring application locally with out any database dependency (kind of mock mode). You can think of million other applications like to make use of Profile concept.

How to set the NetBeans Server in Maven?

I have a Web Application that is environment independent so it's a single war that can be deployed to multiple environments.
I have created multiple Tomcat Servers (i.e. Devel, QA, Production) and defined them in in the NetBeans server configuration.
I'm able to run the war against each of the environments fine by manually changing the project properties but I would like to be able to set what server to connect to from within Maven and either add custom Debug/Run actions or by using maven profiles.
I've tried setting:
<netbeans.deployment.server.id>tomcat70:home=C:\Apache\Tomcat\7.0.34,base=C:\Apache\Tomcat\Devel</netbeans.deployment.server.id>
but that didn't work for me.
Does anyone know if this can be done?
Thanks,
Rob
The proper way to do this is to setup separate profiles in your pom and then have the property set in each of those profiles.

Resources