Spring Boot:执行/stopRunningJobs API时拦截或排队其他请求方案
针对Spring Boot 2.7.0中/stopRunningJobs API的请求控制方案
方案1:执行/stopRunningJobs时阻止接收其他请求
完全可行,核心通过全局状态开关+请求拦截实现,也可以直接操作Servlet容器的连接池彻底拦截请求:
实现方式1:自定义全局过滤器
- 定义原子布尔变量作为全局开关,确保线程安全:
private static final AtomicBoolean STOP_MODE_ACTIVE = new AtomicBoolean(false); - 在
/stopRunningJobs接口逻辑开头将开关设为true,所有Batch任务停止完成后再重置为false - 编写过滤器拦截除
/stopRunningJobs外的所有请求,开关激活时直接返回服务不可用状态
代码示例:
@Component public class RequestBlockFilter implements Filter { private static final AtomicBoolean STOP_MODE_ACTIVE = new AtomicBoolean(false); public static void setStopModeActive(boolean active) { STOP_MODE_ACTIVE.set(active); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; if (STOP_MODE_ACTIVE.get() && !"/stopRunningJobs".equals(httpRequest.getRequestURI())) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); httpResponse.getWriter().write("Service is stopping, please try again later."); return; } chain.doFilter(request, response); } }
对应Controller逻辑:
@PostMapping("/stopRunningJobs") public ResponseEntity<String> stopRunningJobs() { RequestBlockFilter.setStopModeActive(true); try { // 执行停止所有Spring Batch任务的逻辑 stopAllBatchJobs(); return ResponseEntity.ok("All jobs stopped successfully"); } finally { RequestBlockFilter.setStopModeActive(false); } }
实现方式2:操作Servlet容器(以Tomcat为例)
如果需要彻底阻止容器接收新请求,可以直接控制Tomcat的连接器:
@Autowired private ServletWebServerApplicationContext webServerApplicationContext; private void pauseConnector() { TomcatWebServer tomcatWebServer = (TomcatWebServer) webServerApplicationContext.getWebServer(); for (Connector connector : tomcatWebServer.getTomcat().getService().findConnectors()) { connector.pause(); } } private void resumeConnector() { TomcatWebServer tomcatWebServer = (TomcatWebServer) webServerApplicationContext.getWebServer(); for (Connector connector : tomcatWebServer.getTomcat().getService().findConnectors()) { connector.resume(); } }
在/stopRunningJobs接口中,先调用pauseConnector()暂停接收新请求,任务处理完成后调用resumeConnector()恢复。注意这种方式会拦截所有请求,包括/stopRunningJobs本身,需确保该接口的请求已进入处理流程后再执行暂停。
方案2:将新请求排队,待/stopRunningJobs处理完成后恢复
可行,核心是用异步队列缓存请求,待停止操作完成后批量处理:
实现思路
- 同样用全局开关标记停止模式
- 编写拦截器,开关激活时将请求的
AsyncContext存入阻塞队列,暂不处理 - 停止模式结束后,启动线程从队列中取出请求,继续执行原有逻辑
代码示例:
@Component public class RequestQueueFilter implements Filter { private static final AtomicBoolean STOP_MODE_ACTIVE = new AtomicBoolean(false); private static final BlockingQueue<AsyncContext> REQUEST_QUEUE = new LinkedBlockingQueue<>(); public static void setStopModeActive(boolean active) { STOP_MODE_ACTIVE.set(active); if (!active) { // 停止模式结束,批量处理队列中的请求 new Thread(() -> { AsyncContext ctx; while ((ctx = REQUEST_QUEUE.poll()) != null) { try { ctx.dispatch(); } catch (Exception e) { ctx.getResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); ctx.complete(); } } }).start(); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; if (STOP_MODE_ACTIVE.get() && !"/stopRunningJobs".equals(httpRequest.getRequestURI())) { AsyncContext asyncContext = request.startAsync(); // 设置超时时间,避免客户端无限等待 asyncContext.setTimeout(30000); REQUEST_QUEUE.offer(asyncContext); return; } chain.doFilter(request, response); } }
Controller逻辑与方案1一致,在finally块中调用RequestQueueFilter.setStopModeActive(false)触发队列处理。
注意事项
- 根据业务场景设置队列容量,避免内存溢出
- 配置合理的请求超时时间,防止客户端长时间等待
- 高并发场景下建议结合线程池处理队列请求,避免单线程瓶颈
内容的提问来源于stack exchange,提问作者Harish Dalmia
相关产品推荐
相关产品推荐

