In a previous post, I highlighted how we use Gradle to create content jars that can be used in your Spring Boot application.
In this post, I will show you how to overwrite individual files within your content jar to let your server provide a custom configuration.
Let’s say you have created a jar file called myapp.jar. It packages a configuration file using AngularJS constants. However, when you are running your Spring Boot application, you want to provide your own set of values to point at a different server or change timeout values for production.
You could add a complete template engine like Thymeleaf or the Groovy Template Engine. This seems like the right fit for more complex configuration settings. But it is just overkill when all we really want to do is just replace one static file endpoint with another.
Instead, we can provide the SimpleUrlHandlerMapping resource mapping mechanism to simply swap out the file in our jar file with one found on the server.
Say we have a settings.js file in our content jar that provides default definitions. Let’s create a file structure under src/main/resources to provide alternate configurations:
├── aws │ └── scripts │ └── settings.js ├── cloudbees │ └── scripts │ └── settings.js └── heroku └── scripts └── settings.js
We can then add a configuration to overwrite the /scripts/settings.js location with the one in /heroku/scripts/settings.js
@Configuration class SettingsConfiguration { @Value('${currentStack:test}') String stack @Bean SimpleUrlHandlerMapping settingsHandlerMapping() { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping() mapping.setOrder(Integer.MIN_VALUE) mapping.setUrlMap(Collections.singletonMap("scripts/settings.js", settingsRequestHandler())) mapping } @Bean ResourceHttpRequestHandler settingsRequestHandler() { ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler() requestHandler.setLocations(Arrays .<Resource> asList(new ClassPathResource("/${stack}/"))) // <----- rewrite requestHandler } }
With the rewrite logic in place, we can then deploy our fat jar in different services and serve out different service configurations based on the stack variable.
Using this approach, we can keep our configuration files in Javascript instead of a messy combination of template languages and externalized property files.