This provides a springboot starter for the official Unleash Client SDK for Java. This takes care of the required bootstrapping and creation of Unleash client. This also provides a annotation based approach to feature toggling similar to the functionality provided by FF4J client library. This also takes care of adding the unleash sdk as a transitive dependency.
The following dependency needs to be added to the springboot project pom.
<dependency>
<groupId>io.getunleash</groupId>
<artifactId>springboot-unleash-starter</artifactId>
<version>Latest version here</version>
</dependency>
io:
getunleash:
app-name: <application-name>
instance-id: <instance-id>
environment: <environment>
api-url: <url>
api-token: <token>
ex:
io:
getunleash:
app-name: springboot-test
instance-id: instance x
environment: development
api-url: http://unleash.herokuapp.com/api/
api-token: '*:development.21a0a7f37e3ee92a0e601560808894ee242544996cdsdsdefgsfgdf'
- The configuration takes care of creating configuring
UnleashConfig
and creating an instance ofio.getunleash.Unleash
. - This takes care of binding all strategy instances (in-built and custom) to the
Unleash
instance.
Provide an UnleashContextProvider
bean to add details that Unleash can leverage when evaluating toggle strategies:
@Bean
@ConditionalOnMissingBean
public UnleashContextProvider unleashContextProvider(final UnleashProperties unleashProperties) {
return () -> {
UnleashContext.Builder builder = UnleashContext.builder();
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof User) {
builder.userId(((User)principal).getUsername());
}
return builder
.appName(unleashProperties.getAppName())
.environment(unleashProperties.getEnvironment())
.build();
};
}
- Create a feature toggle
demo-toggle
on unleash server and enabled it. - Create an interface FeatureDemoService and 2 implementation
public interface FeatureDemoService {
String getDemoString(String name);
}
@Service("featureOldService")
public class FeatureDemoOldServiceImpl implements FeatureDemoService {
public String getDemoString(String name) {
return "old implementation";
}
}
@Service("featureNewService")
public class FeatureDemoNewServiceImpl implements FeatureDemoService {
public String getDemoString(String name) {
return "New implementation";
}
}
- The requirement is that if the feature is enabled on the server, the new service implementation is used.
- To get the above functionality add the
@Toggle
annotation to the interface, - If
Context
annotation is not used and UnleashContext is explicitly passed as a method parameter
import io.getunleash.UnleashContext;
import org.unleash.features.annotation.Toggle;
public interface FeatureDemoService {
@Toggle(name="demo-toggle", alterBean="featureNewService")
String getDemoString(String name, UnleashContext context);
}
- If
@Context
annotation is used to set UnleashContext
import io.getunleash.UnleashContext;
import org.unleash.features.annotation.Toggle;
public interface FeatureDemoService {
@Toggle(name="demo-toggle", alterBean="featureNewService")
String getDemoString(String name);
}
FeatureDemoService
is injected where required.
- If
Context
annotation is not used and UnleashContext is explicitly passed as a method parameter
import io.getunleash.UnleashContext;
import org.unleash.features.annotation.Toggle;
public interface FeatureDemoService {
@Toggle(name="demo-toggle", alterBean="featureNewService")
String getDemoString(String name, UnleashContext context);
}
@RestController
@RequestMapping("/feature")
public class FeatureDemoController {
private final FeatureDemoService featureDemoService;
public FeatureDemoController(@Qualifier("featureOldService") final FeatureDemoService featureDemoService) {
this.featureDemoService = featureDemoService;
}
@GetMapping
public String feature(@RequestMapping final String name) {
return featureDemoService.getDemoString(name, UnleashContext.builder().addProperty("name", name).build());
}
}
- If
@Context
annotation is used to set UnleashContext
import io.getunleash.UnleashContext;
import org.unleash.features.annotation.Toggle;
public interface FeatureDemoService {
@Toggle(name="demo-toggle", alterBean="featureNewService")
String getDemoString(String name);
}
@RestController
@RequestMapping("/feature")
public class FeatureDemoController {
private final FeatureDemoService featureDemoService;
public FeatureDemoController(@Qualifier("featureOldService") final FeatureDemoService featureDemoService) {
this.featureDemoService = featureDemoService;
}
@GetMapping
public String feature(@RequestMapping @Context(name = "name") final String name) {
return featureDemoService.getDemoString(name);
}
}
- With the above, if the
demo-toggle
feature is enabled, thefeatureNewService
is called even thoughfeatureOldService
was injected.
-
Toggle annotation has support for variants. It can be used as follows:
@Toggle(name = "background-color-feature", variants = @FeatureVariants( fallbackBean = "noBackgroundColorService", variants = { @FeatureVariant(name = "green-background-variant", variantBean = "greenBackgroundColorService"), @FeatureVariant(name = "red-background-variant", variantBean = "redBackgroundColorService") }))
- In the above example, there are 2 variants
green-background-variant
andred-background-variant
defined in unleash. Here the implementation to be used for each variant is defined.fallbackBean
is the implementation that will be used if a variant to bean mapping is not found.
- In the above example, there are 2 variants
-
git link to example app below:
If you have push rights to the repo, make sure there are no modifications that haven't been checked in. Then run
mvn release:prepare
and answer the prompts for new release version.
Once that's done, a new tag should've been created in the repo, and the deploy release workflow will do the actual deploy.
Then, run mvn release:clean to clean your repo for release artifacts which only clutters up the main branch. This will leave you