Whether you like it or not, software development is a collaborative activity. Integration work has always been demonized and treated as necessary evil. There are several approaches which try to solve the challenge of effective integration. The feature toggle belongs to that group. In this article, you’ll see in practice how feature toggles, also known as feature flags, can be used in your Spring Boot application.
Advertisement
1. What is feature toggle?
Simply put, Feature toggles are variables which allow execution of alternative paths in an application based on their current values. By keeping different scenarios of execution, you can modify the behavior of the application without altering the code.
Depending on your needs, toggles’ values can be set before the startup of your application or adjusted at runtime. In the latter case, changes of a value can be persisted or affect only the current execution of the application.
Usually, you read about feature flags as an alternative for feature source code branching, however, in practice both techniques can be used together. For instance, you can use feature branches for development of new user stories in the application, while feature toggles can be applied to control access to features on separate environments (e.g. clients with different requirements).
Despite many uses, feature toggles have also their drawbacks. The biggest one is complexity. Without a proper strategy they can quickly get out of hand and become a maintenance nightmare. Fortunately, if you follow several good practice and organize the application around features, working with feature flags should be much simpler.
2. Selecting beans with feature toggle
The most common case for using feature toggles in a Spring Boot application is activating a different implementation of some interface based on a current value of a feature toggle. Let’s examine an example to demonstrate described case.
2.1 Dependency abstraction
Imagine you have a web endpoint which returns a list of products fetched from a database repository. Your goal is to create a feature toggle that allows switching repository implementation to one that uses a web service as a data source.
If the class you want to allow for feature toggling is directly used in other classes, the first thing you need to do is to abstract the dependency using an interface.
The snippet below presents an example product REST endpoint which depends on a ProductRepository interface.
@RestController @RequestMapping("/products") class ProductController { private final ProductRepository productRepository; ProductController(ProductRepository productRepository) { this.productRepository = productRepository; } @GetMapping Collection<Product> getAll() { return productRepository.findAll(); } }
At this moment, we have only one implementation of the interface. Soon we’re going to add another one, which you’ll activate with a feature toggle.
@Repository class DbProductRepository implements ProductRepository { //... }
2.2 Feature toggle in application.properties
Since the application.properties file is used for configuration of your Spring Boot application, it’s a great place for putting your feature toggle flag.
feature.toggles.productsFromWebService=true
Set the flag to false before committing the code. This way, by default your teammates will have the new feature disabled. If someone wants to activate the feature, their can change the flag value to true on the local development environment.
2.3 Conditional bean creation
Your next step is to create an alternative implementation of the interface that you want to activate with the feature toggle. In order to instantiate the bean based on the value of the created property, you can use Spring Boot annotation called @ConditionalOnProperty. Set the name of the toggle property and the value which should activate it. The value should be the same as the one placed in the application.properties file.
@Repository @ConditionalOnProperty( name = "feature.toggles.productsFromWebService", havingValue = "true" ) class WebServiceProductRepository implements ProductRepository { //... }
Before you start your application, you have to disable the database repository, otherwise, you will get an exception about multiple active implementations of the interface. Return to the the first implementation and apply the following changes:
@Repository @ConditionalOnProperty( name = "feature.toggles.productsFromWebService", havingValue = "false", matchIfMissing = true ) class DbProductRepository implements ProductRepository {
We use the same feature toggle name as previously, only its value has changed. Setting the matchIfMissing property is optional. By doing this, if you remove the feature toggle form the application.properties file, this bean will be created even though the value is missing.
3. How to disable controller with feature toggle
You can apply the same strategy to conditionally activate a whole Spring web controller. You don’t need to create an additional interface because there is only one implementation that you want to control with the feature toggle.
@RestController @RequestMapping("/coupons") @ConditionalOnProperty(name = "feature.toggles.coupons", havingValue = "true") class CouponController { //... }
The application.properties should contain the following line.
feature.toggles.coupons=true
When you don’t set the value to true, the controller won’t be instantiated by Spring. The client will simply receive the 404 HTTP status code.
Unfortunately, the @ConditionalOnProperty annotation can’t be used on a single @RequestMapping method. As a workaround, you can move the desired mapping to a separate controller bean. Alternatively, it’s possible to simply inject the value of the feature toggle and create an if statement in the body of the mapping method. However, you should use this solution with caution. If you’re interested why you’ll find the answer in the next paragraph.
private final boolean couponsToggled; CouponController(@Value("${feature.toggles.coupons}") boolean couponsToggled) { this.couponsToggled = couponsToggled; } @GetMapping List<String> listCouponNames() { if (!couponsToggled) { throw new NotSupportedException(); } //... }
4. Multiple feature toggle management
As you can read about feature toggles on Martin Fowler’s bliki, feature flags have a tendency to spread across the codebase and can quickly get unmanageable. Even if you have just a few feature toggles in your application, it’s better to abstract the storage of your flags from decision points in which they are used.
4.1 Avoiding feature flag coupling
The last code example from the previous paragraph uses the flag value injected directly from the application.properties file, therefore it doesn’t abstract the storage. If you want to use the same flag in a different part of your application, you’ll have to duplicate the injection.
What you can do instead is to put all feature toggle values inside a single class, which will act as a single source of truth. Using a separate class gives you much more flexibility. For instance, you could replace the storage of flags with a database or implement a mechanism which allows switching flags at runtime.
4.2 Extracting feature toggle decisions in Spring Boot
Once you have a separate bean for your feature toggles, you can easily inject all flags from the application.properties file using the @ConfigurationProperties annotation. Here you can see a sample implementation:
@Component @Component @ConfigurationProperties("feature") public class FeatureDecisions { private Map<String, Boolean> toggles = new HashMap<>(); public Map<String, Boolean> getToggles() { return toggles; } public boolean couponEnabled() { return toggles.getOrDefault("coupons", false); } }
The class above will take all properties which start with feature.toggles and put them in the toggles map. As you can see, there’s a method called couponEnabled() which you can use to abstract a feature decision point from the logic behind that decision.
In addition, you’ll also need an extra dependency to enable processing for @ConfigurationProperties.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency>
5. Actuator endpoint for feature toggles
Since you already have all feature toggles in a single place, all you have to do now is to expose the list using a custom Actuator endpoint. The following example will show you how to do it.
@Component @Endpoint(id = "feature-toggles") class FeatureToggleInfoEndpoint { private final FeatureDecisions featureDecisions; FeatureToggleInfoEndpoint(FeatureDecisions featureDecisions) { this.featureDecisions = featureDecisions; } @ReadOperation public Map<String, Boolean> featureToggles() { return featureDecisions.getToggles(); } }
If you work with the default Spring Boot 2 Actuator setup, the endpoint won’t be exposed via HTTP. In order to test it in your browser, you have to enable the Actuator endpoint by adding its identifier to the web include filter in your application.properties file.
management.endpoints.web.exposure.include=health,info,feature-toggles
Once you run your application, go to http://localhost:8080/actuator/feature-toggles to see the results returned by the endpoint:
Depending on your needs, you could also implement the possibility to switch feature toggles at runtime using @WriteOperation on the created endpoint. This example covers only the output part.
Conclusion
In this article, you could learn about practical examples of feature toggles in a Spring Boot application. We started with a very basic sample in which the framework covers all the needs. After that, we write some custom code to complete more custom feature toggle requirements. We finished with the helpful Actuator endpoint for displaying the status of all feature flags in the application.
You can find the working sample application in the Github repository. If you like the post and find it useful, please share it with your followers. I’m also looking forward to your questions and comments below the article.
Hi Daniel. Thanks for this great article. Could you explain in your opinion what are the difference between using feature toggles with @ConditionalOnProperty annotation or using @Profile that allows too to activate or deactivate beans based on the property spring.profiles.active?. I think the result are really the same. Maybe @ConditionalOnProperty are more versatile. What do you think?
Hi Esteban. This is a very good question.
Your way of thinking is correct. From the technical perspective there’s no difference between @ConditionalOnProperty and @Profile. You’ll achieve conditional bean registration with both approaches. In my personal opinion, it’s more about the way you look at them.
In most cases, I use profiles to segregate global application configurations for different deployment environments. Environments are reflected by profiles’ names. Feature toggles work on a lower level of granularity and affect smaller parts of an application (ideally just a single bean).
In my experience, profiles are commonly associated with environments. But if you have a different approach and use them just to group parts of your application, they can work just fine as a replacement for @Conditionals.
I would be grateful if you could share how you utilize profiles. I believe it might be inspiring.
Hi Daniel. Thanks for your answer. It clarified me my doubts. I usually use @profile to define environments settings. I didn’t know anything about @ConditionalOnProperty until I did read your article. Thanks again.
Thanks for sharing that, and I’m glad my content has been valuable to you.