如何通过特性标志服务批量启用/禁用Spring Boot应用所有控制器?
一次性启用/禁用Spring Boot所有控制器的方案
针对你的需求,不用在每个控制器加判断,有两种实用方案,分别适合运行时动态开关和启动时静态开关的场景:
方案一:全局请求拦截器(运行时动态生效)
通过Spring MVC的HandlerInterceptor拦截所有请求,在请求到达控制器前检查特性标志,直接拦截禁用状态下的请求。
实现步骤:
- 编写全局拦截器类,注入你的特性标志服务,在
preHandle方法中判断开关状态:
@Component public class GlobalControllerToggleInterceptor implements HandlerInterceptor { private final FeatureFlagService featureFlagService; public GlobalControllerToggleInterceptor(FeatureFlagService featureFlagService) { this.featureFlagService = featureFlagService; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { boolean controllersEnabled = featureFlagService.isControllersEnabled(); if (!controllersEnabled) { // 返回503服务不可用,可根据需求修改响应内容和状态码 response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); response.getWriter().write("Controllers are temporarily disabled"); return false; // 终止请求流转,不会到达控制器 } return true; // 放行请求到控制器 } }
- 注册拦截器,让它拦截所有路径(可按需排除健康检查、Actuator等特殊端点):
@Configuration public class WebMvcConfig implements WebMvcConfigurer { private final GlobalControllerToggleInterceptor toggleInterceptor; public WebMvcConfig(GlobalControllerToggleInterceptor toggleInterceptor) { this.toggleInterceptor = toggleInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(toggleInterceptor) .addPathPatterns("/**") // 拦截所有请求 .excludePathPatterns("/actuator/health", "/actuator/info"); // 排除不需要拦截的路径 } }
这个方案的优势是运行时动态生效,修改特性标志后无需重启应用,立即生效。
方案二:@Conditional条件注解(启动时生效)
如果你的开关不需要运行时动态调整,仅在启动阶段决定是否启用控制器,可以用Spring的@Conditional注解实现。
实现步骤:
- 自定义条件判断类,读取特性标志的值:
public class ControllersEnabledCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 这里假设特性标志可通过环境变量获取,或直接注入你的FeatureFlagService(需通过ApplicationContext获取) Environment env = context.getEnvironment(); return Boolean.parseBoolean(env.getProperty("feature.controllers.enabled", "true")); } }
- 在启动类或控制器扫描配置上添加条件,仅当开关为
true时才扫描并注册控制器:
@SpringBootApplication @ComponentScan( basePackages = "com.yourpackage", includeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, value = RestController.class ), useDefaultFilters = false ) @Conditional(ControllersEnabledCondition.class) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
或者给每个控制器类直接添加@Conditional(ControllersEnabledCondition.class),但批量扫描的方式更高效。
这个方案的特点是启动时一次性决定,开关状态在应用运行期间无法动态修改,适合不需要频繁变更的场景。
内容的提问来源于stack exchange,提问作者Đức Trường Đặng
相关产品推荐
相关产品推荐

