In our last post, we discussed how to externalize application properties in Spring Boot applications.
That would work well for single, standalone applications. However, when we have more than one application, say in a microservice architecture, a better alternative would be to manage the configurations centrally. That can be easily done using Spring Cloud Config. We can have a centralized configuration service just by creating a Spring Boot application with a
spring-cloud-config-server dependency, annotating the auto-generated main class with
@EnableConfigServer, and then having the following in src/main/resources/application.yml:
spring: cloud: config: server: git: uri: https://path/to/config-repo username: xxxxxxxxxx password: yyyyyyyyyy server: port: 8888
The URI above points to a git repository where your properties/yml files would be lying. For example, if you have two services, say service1 and service2, you could have the following files in the config-repo:
- application.yml: all the common configurations
- service1.yml: configurations for service1
- service2.yml: configurations for service2
- application-dev.yml: common configurations for the dev profile
- application-test.yml: common configurations for the test profile
- application-prod.yml: common configurations for the prod profile
- service1-dev.yml: configurations for service1 for the dev profile
- … and so on.
If one property is defined in multiple files, the last one in the above order will take precedence.
Spring Cloud Config provides us many options and alternatives, which can be found in its documentation.
So, our services can now have just a single file at src/main/resources,
bootstrap.yml, looking as below:
spring: application: name: service1 profiles: active: dev cloud: config: uri: http://localhost:8888 label: branch1,branch2,...
The above should work, but we now have an interesting problem – how to maintain different configurations for different feature branches?
How to maintain different configurations for different feature branches
If you noticed in the bootstrap.yml above, we have
label: branch1,branch2,.... Consequently, configurations will be fetched from
branch1 of the config-repo. In the absence of branch1, branch2 would be looked for, and so on. If you omit that line above, the master branch would be used.
With the above knowledge, we can set the label appropriately to point to the correct configuration branch. For example, when working on a feature branch, have
label: feature1,develop, and when you merge your code to another branch, remember to change the label accordingly.
Obviously, it’s cumbersome to keep changing the labels manually when merging branches. So, here’s a way to automate it:
1) Generate a git.properties file
Let your build process generate a git.properties file. Googling will get you many ways, I’d recommend to follow the Spring Boot Documentation.
2) Use the git.branch variable in the label
For example, assuming your code is branched in the following structure:
master |- develop |- feature1 |- feature2 |- ...
You can set label in bootstrap.yml as below:
3) Inject git.branch in the variable above
This is the most tricky part. A normal way to do this would be to annotate some configuration class with
@PropertySource("classpath:git.properties"), as below:
@SpringBootApplication @PropertySource("classpath:git.properties") // won't work! public class Service1Application ...
But, this won’t work, because the label property in bootstrap.yml would be used before git.properties is read!