A code example showing a simple way to feature flag in Java and Spring eliminating the code and checks when the flag is disabled.
Overview
There are many ways to do feature flags in Java and Spring and some excellent articles are listed at the bottom of this post.
However where possible this is my favourite technique because it eliminates the usual flag checking for each call.
Instead, the check is done once at start-up and the whole component is either enabled or disabled.
If the flag is disabled, then no further checks are done.
Getting The Code
The example is a simple rest controller that we turn off and on.
You can check out, build, test and run as below.
git clone https://github.com/johndobie-blog/feature-flag.git
mvn clean test spring-boot:run
Understanding The Example
We use a simple REST Controller that echoes any message that is passed.
public class EchoController {
public static final String ECHO_ENDPOINT = "/echo";
@GetMapping(ECHO_ENDPOINT)
public String echo(@RequestParam String message) {
return message;
}
}
Adding The Flag
We can add the flag echo.enabled as below.
@ConditionalOnProperty
(name = "echo.enabled", havingingValue="true "matchIfMissing = false)
By default, if that flag is not set to true, the controller will not be enabled.
This is the safest way IMHO.
@RestController
@ConditionalOnProperty(name = "echo.enabled", havingValue = "true", matchIfMissing = false)
public class EchoController {
public static final String ECHO_ENDPOINT = "/echo";
@GetMapping(ECHO_ENDPOINT)
public String echo(@RequestParam String message) {
return message;
}
}
You can change to matchIfMissing to true.
Then the default behaviour will be to always enable the controller, unless the flag is specifically set to false.
Testing With The Flag On
First we can test that with the flag enabled, that the controller is loaded.
@TestPropertySource(properties = {“echo.enabled=true”})
@WebMvcTest(controllers = EchoController.class)
@TestPropertySource(properties = {"echo.enabled=true"})
public class EchoControllerEnabledMvcTest {
private static final String MESSAGE = "Hello, World";
@Autowired
private MockMvc mockMvc;
@Test
public void getShouldReturnMessage() throws Exception {
this.mockMvc
.perform(get(ECHO_ENDPOINT)
.param("message", MESSAGE))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(MESSAGE)));
}
}
We can see that the message is successfully echoed from the controller
Testing With The Flag Off
A similar test can be used to check we get an error when the flag is disabled.
@TestPropertySource(properties = {“echo.enabled=false”})
@WebMvcTest(controllers = EchoController.class)
@TestPropertySource(properties = {"echo.enabled=false"})
public class EchoControllerDisabledMvcTest {
private static final String MESSAGE = "Hello, World";
@Autowired
private MockMvc mockMvc;
@Test
public void getShouldReturnError() throws Exception {
this.mockMvc
.perform(get(ECHO_ENDPOINT)
.param("message", MESSAGE))
.andDo(print())
.andExpect(status().is4xxClientError());
}
}
ShellScriptIn this case an error is returned because the controller does not exist.
Running The Application Standalone
When running the application the flag is set in properties as below.
echo.enabled=true
You can then test as follows.
mvn spring-boot:run
Then disable the feature and start again
echo.enabled=false
Wrap up
This is a great way to implement feature flags that will only run at start-up.
This technique cannot be used in all circumstances, but is great for situations where you want to enable or disable whole components.
Further Info
Check out these resources for more detailed info on feature flags
https://martinfowler.com/articles/feature-toggles.html
https://www.baeldung.com/spring-feature-flags
Leave a Reply
You must be logged in to post a comment.