Mastering Feature Toggles in Spring Boot 3: 6 Practical Implementations
This article explains why feature flags are essential in Spring Boot projects and walks through six concrete ways to implement dynamic toggles—including @Profile, @Conditional, @RefreshScope, database‑backed scheduling, Apache Commons Configuration, and Togglz—complete with code snippets and usage tips.
In Spring Boot projects, feature flags (Feature Toggles) allow dynamic control of business logic or modules, enabling gray releases, risk isolation, and fine‑grained operations.
By decoupling flag configuration from code, developers can adjust status via configuration centers (Nacos, Consul), databases, or local files without restarting services. Typical scenarios include small‑scale validation before new feature rollout, emergency rollback of major events, A/B testing, and fault isolation.
This article presents six practical implementations of feature toggles in Spring Boot 3.4.2.
1. Using @Profile Annotation
@Profile marks a component to be registered only when specified profiles are active. Example:
<code>@Component
@Profile({"prod"})
public class CommonComponent {
@PostConstruct
public void init() {
System.err.println("CommonComponent init...");
}
}
</code>The component registers only if spring.profiles.active includes "prod". When applied to @Configuration , all @Bean and @Import within are active only for the specified profile.
Logical operators can be used in @Profile , e.g. "!prod", "prod && ss".
<code>// Activate when profile is not prod
@Profile("!prod")
// Activate when both prod and ss are active
@Profile("prod && ss")
</code>2. Using @Conditional Annotation
@Conditional (or its meta‑annotation @ConditionalOnProperty ) registers a bean only when all specified conditions are met.
<code>@Component
@ConditionalOnProperty(prefix = "pack.app", name = "enabled", havingValue = "true", matchIfMissing = true)
public class CommonComponent {
@PostConstruct
public void init() {
System.err.println("CommonComponent init...");
}
}
</code>Only when pack.app.enabled=true (or missing) the component is created.
3. Using @RefreshScope (Spring Cloud)
Add Spring Cloud dependencies and enable bootstrap.yml . Annotate beans with @RefreshScope to allow runtime refresh via /actuator/refresh .
<code>@RefreshScope
@Component
@ConfigurationProperties(prefix = "pack.toggle")
public class CommonComponent {
private boolean enabled;
// getters and setters
}
</code>Initial configuration in bootstrap.yml :
<code>pack:
toggle:
enabled: false
</code>After changing the value to true and calling /refresh , the new property is applied.
4. Database‑Backed Toggle with @Scheduled
Persist toggle state in a database table and poll it periodically.
<code>@Entity
@Table(name = "t_prop_config")
public class PropConfig {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String propKey;
private String propValue;
}
</code>Repository query:
<code>@Query("select propValue from PropConfig")
String findByPropKey(String propKey);
</code>Scheduled task reads the value:
<code>@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
public void init() {
String propKey = this.propConfigRepository.findByPropKey("pack.toggle.enabled");
if (StringUtils.hasLength(propKey)) {
this.enabled = Boolean.valueOf(propKey);
System.err.printf("pack.toggle.enabled = %s%n", this.enabled);
}
}
</code>5. Using Apache Commons Configuration
Commons Configuration2 can reload a properties file periodically.
<code>@Component
public class FeatureConfigManager {
private ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder;
private static final String filePath = "app.properties";
@PostConstruct
public void init() throws Exception {
Parameters params = new Parameters();
ClassPathResource resource = new ClassPathResource(filePath);
builder = new ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class)
.configure(params.fileBased().setFile(resource.getFile()));
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(
builder.getReloadingController(), null, 5, TimeUnit.SECONDS);
trigger.start();
}
public boolean isFeatureEnabled(String key) {
try {
return builder.getConfiguration().getBoolean(key, false);
} catch (ConfigurationException e) {
return false;
}
}
}
</code>Expose via a REST controller:
<code>@RestController
@RequestMapping("/config")
public class ConfigController {
private final FeatureConfigManager config;
public ConfigController(FeatureConfigManager config) {
this.config = config;
}
@GetMapping("")
public boolean get() {
return this.config.isFeatureEnabled("pack.toggle.enabled");
}
}
</code>6. Using Togglz Library
Togglz provides a ready‑made feature‑toggle implementation. Refer to the linked article for detailed usage.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.