Spring Boot and Webjars – overwriting configuration during runtime

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s