Feature toggle implementation using Spring boot

A Feature toggle (also known as feature switch, feature flag, feature flipper, conditional feature, etc.) is a technique in software development that is used to hide, enable or disable the feature during run time. Feature toggle implementation is very common agile development practices in the context of continuous deployment and delivery. We can enable or disable these features at application runtime.

Feature toggles are variables that are used inside conditional statements therefore, the logic inside these blocks can be toggled 'on or off' depending on the value of the feature toggles. A block of code which has been toggled 'off' is similar to being commented out. This allows developers to control the flow of their software and bypass features that are not ready for deployment.

Features toggles can be used in the following scenarios.

1. Adding a new feature to an application

2. Enhancing an existing feature in an application

3. Hiding or disabling a feature

4. Extending an interface

Features toggles can be stored as 

1. Row entires in a database.

2. A Property in a configuration file. 

In this article I am showing one example of implementing feature toggle using spring boot application. Create a spring boot application with gradle and add togglz spring boot starter dependencies. In this example I am using mongo db for storing feature toggles.










Add following dependencies in the build.gradle file

compile("org.togglz:togglz-console:2.4.1.Final")
compile("org.togglz:togglz-spring-security:2.4.1.Final")
compile("com.github.heneke.thymeleaf:thymeleaf-extras-togglz:1.0.1.RELEASE")
compile('org.springframework.boot:spring-boot-starter-data-mongodb')
// https://mvnrepository.com/artifact/org.togglz/togglz-mongodb
compile group: 'org.togglz', name: 'togglz-mongodb', version: '2.4.1.Final'

Define your features in enum like below

public enum MyFeatures implements Feature {

    @Label("First Feature")
    FEATURE_ONE,
    
    @Label("Second Feature")
    FEATURE_TWO;
    
    public boolean isActive() {
        return FeatureContext.getFeatureManager().isActive(this);
    }
    
}

ToggleFeature.java

package com.example.demo;


public class ToggleFeature {

	private String name;
	private boolean active;
	
	public ToggleFeature(){
	}
	
	public ToggleFeature(String name, boolean active){
		this.name = name;
		this.active = active;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}
}

Provide toggle configuration like below

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.togglz.core.repository.StateRepository;
import org.togglz.core.user.NoOpUserProvider;
import org.togglz.core.user.UserProvider;
import org.togglz.mongodb.MongoStateRepository;

import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;

@Configuration
public class ToggleConfig {
	private static final String FEATURE_TOGGLE_TABLE = "feature_toggle_table";


    @Autowired
    private MongoClient mongoClient;

    @Bean
    public UserProvider userProvider() {
        return new NoOpUserProvider();
    }

    @Bean
    public StateRepository getStateRepository() {
    	
		StateRepository repository = MongoStateRepository
    		     .newBuilder(mongoClient, "demo")
    		     .collection(FEATURE_TOGGLE_TABLE)
    		     //.authentication("john", "tiger")
    		     .writeConcern(WriteConcern.W1)
    		     .build();
    	
        return repository;
    }
}

application.properties file

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=demo

Implemented one REST controller for enabling are disabling features.

package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.togglz.core.context.FeatureContext;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.repository.FeatureState;

import com.example.demo.MyFeatures;
import com.example.demo.ToggleFeature;

@RestController
public class FeatureToggleController {

	@Autowired
	private FeatureManager manager;
	
	@RequestMapping(value = "/feature/{name}", method = RequestMethod.POST)
	public ResponseEntity<ToggleFeature> setFeatureStatus(@PathVariable String name,
			@RequestBody ToggleFeature resource) {
		FeatureContext.getFeatureManager()
				.setFeatureState(new FeatureState(MyFeatures.valueOf(name), resource.isActive()));
		return ResponseEntity.ok(new ToggleFeature(name, MyFeatures.valueOf(name).isActive()));
	}

	@RequestMapping(value = "/featureToggles", method = RequestMethod.GET)
	public ResponseEntity<StringBuffer> sayHello() {
		StringBuffer sb = new StringBuffer();
		
		if(manager.isActive(MyFeatures.FEATURE_ONE)){
			sb.append("FEATURE_ONE is enabled");
		}else{
			sb.append("FEATURE_ONE is not enabled");
		}
		
		if(manager.isActive(MyFeatures.FEATURE_TWO)){
			sb.append("\nFEATURE_TWO is enabled");
		}else{
			sb.append("\nFEATURE_TWO is not enabled");
		}
		return ResponseEntity.ok(sb);
	}
}

After starting spring boot application hit the following url

http://localhost:8080/featureToggles

Currently both features are disabled. Hit the following url to enable FEATURE_ONE toggle and pass the FeatureToggle JSON information as part of body.

http://localhost:8080/feature/FEATURE_ONE

After above operation the feature has been enabled in mongo db.

Now if you hit the following url it will show that FEATURE_ONE toggle is enabled.

Like this we can enable or disable features at runtime.


Thanks,

Keep learning :)



Hendi Santika

Chief Executive Officer at JVM Indonesia

6y

Nice sample. But, I think it's better if you save in github repository. It would be helpful

Like
Reply

To view or add a comment, sign in

More articles by Venkata Krishna Jonnabhatla

  • Containerized Microservices

    Microservices and container technologies have become hot trends in application development these days. Microservice…

Others also viewed

Explore content categories