Spring Environment profiles and server properties - spring

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.

Related

Spring Boot: Handle configuration in multitenant application

I am implementing a Spring Boot application which will be providing a multitenant environment. That is achieved in my case by using a database schema for each customer. Example see this project.
Now I am wondering how to implement tenant-specific configurations. I am using #ConfigurationProperties to bundle my property values, but these are getting instantiated once and not for each tenant.
What if I would like to use Spring Cloud Config with multiple tenant specific git repository as an configuration backend. Would it be possible when using a jdbc backend for Spring Cloud Config?
Is there any way with default Spring mechanisms or do I have to implement a database based configuration framework myself?
Edit: For example I have two tenants called Tenant1 and Tenant2. Both are running over the same application in the same context and are writing in the database schemes tenant_1 and tenant_2.
Identification of tenants is happening over keycloak (see Spring Keycloak multi tenant example). So I identify the tenantId from the jwt token and select the database connection like described here.
But now I would need the same mechanism for #Configuration beans. Since #Configuration beans are as far as I know Singletons, so there is always ONE configuration per application scope, and not ONE configuration per tenant.
So using Spring Cloud Config Tenant1 is using https://git-url/tenant1, Tenant2 is using Hashicorp Vault as backend and perhaps Tenant3 will be using a jdbc based configuration backend. And all of that in ONE (of course scalable) application.
In case your application uses tenant specific files (html templates etc), the following can be applied. As I have used the below approach for handling many tenants and works fine and easy to maintain.
I would suggest that you maintain a consistent configuration source (JDBC) for all of your tenant configurations. This helps you have a single source that is cacheable and scalable for your application. Also, you could have your tenants navigate to a configuration page to manage their settings and alter them to suit their needs at any point of time on the fly. (Example Settings: Records Per Page, Theme, Logo, Filters etc...)
Having the tenant configuration in files in git will be a difficult task when you wanted to auto-provision tenant's when they sign-up as it will involve couple of distributed services. Having them in a TenantSettings table with the tenantId as a column could help you get the data in no time and will be easy.
You can use Spring Cloud Config for your scenario and it is adoptable. It is easily configurable and provides out of the box features. For your specific scenario, you can have any number of microservices running yet all controlled by one Spring Cloud Config Server which is connected to one Git Repository. Your all microservices are asking configuration properties from Spring Cloud Config Server and it is directly fetching properties from Git Repository. That repository can have multiple property files. It can hold common properties for all the microservices or specific service based configuration properties. If you want to keep confidential properties more securely, that is also made possible via HashiCorp vault. I will leave an image below for you to get a better idea about this concept.
In the below image, you can see the Git Repository with common configuration property files and specific configuration property files for different services yet in same repository.
I will add another image for you to get a better idea how does this can be arranged with application profiles as well.
Finally I will add something additional to show the power of Spring Cloud Config and out of the box features it allows us to play with. You can automatically refresh configuration properties in running application as well. You can configure Spring Cloud Config to do that. I will add an architectural diagram to achieve that.
References for this answer is taken from Spring in Action, Fifth Edition
Craig Walls

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 Roo #RooJpaActiveRecord parameterized the JPA table catalog

I need a why to change the JPA catalog element in my java class? We have many database environments which we need to be able to deploy our application too. Example: In your dev environment we have a database for new development, and production support. All database live on the same server so we have the following database names: am_web_dd and am_web_ps. So we need to be able to change the catalog at build time or start up time. We've thought of using Maven to do a search and replace during build but I was wondering if there is a way of doing this with a parameter?
Here is one of our #RooJpaActiceRecord statements:
#RooJpaActiveRecord(catalog = "am_web_t4", schema = "dbo", table = "user_t")
I would like to be able to make catalog a parameter. Is this possible? if not what would be the best approach?
Thank you for your time!
I know it is possible from a JPA standpoint, but I don't think you will be able to using straight Roo. This might help.
There may also be a way to use a Java Configuration object in Spring to build your JPA Entity Manager. I think that's were you want to set it.
The approach you suggest of making catalog dynamic would be suitable if you wanted to let the user choose/change the schema on demand, however, it looks like this is not your requirements, so I would steer away from this path as it more difficult than you need.
You can use spring profiles to define different database connections and use an environment variable to define which one is active. Spring profiles can be set in XML or java configuration classes.

Applying settings in Spring based application in runtime

We have Spring based (Spring.NET) web application and use VariablePlaceholderConfigurer to keep some settings in a separate properties file.
These properties are mainly different values affecting business logic, like emails, timeouts, paths, etc.
Now we need to implement administrative UI to allow users to change these settings in more friendly way.
So we will move all these settings to a database.
Question: What is the best (standard, common) approach to implementing settings like I described in Spring based application? (Assuming we want changes to be effective immediately without application restart.)
It is good if we can keep our current approach when setting values as just properties of beans.
The VariablePlaceholderConfigurer is ObjectFactoryPostProcessor, which is only invoked after reading the object definitions. So you cannot simply introduce a new IVariableSource that you refer to in your VariablePlaceholderConfigurer configuration, because it will only take effect after container reload.
You have to create an IObjectObjectPostProcessor to modify properties on container managed objects at runtime.

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

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

Resources