You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC中从Rest Controller调用Scheduler并获取定时任务返回结果

解决方案

1 改造定时任务类,实现结果共享

首先需要在线程安全的前提下存储定时任务每次执行的最新结果,直接修改你现有的StartupBean即可,Spring单例模式下Controller和定时任务可以共享该Bean内的成员变量:

@Component
public class StartupBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(StartupBean.class);
    // volatile保证多线程下的结果可见性,存储定时任务返回的JSON对象
    private volatile Object latestSessionCountResult;
    // 标记任务运行状态,避免重复启动Timer
    private volatile boolean isRunning = false;

    public void start() throws Exception {
        if (isRunning) {
            return;
        }
        isRunning = true;
        LOGGER.info("Entering start method {}", System.currentTimeMillis());
        try {
            TimerTask counterTimerTask = new SessionCountTask() {
                @Override
                public void run() {
                    // 此处替换为你SessionCountTask中实际返回JSON的方法名
                    Object jsonResult = this.generateJsonResult();
                    // 更新最新结果
                    latestSessionCountResult = jsonResult;
                }
            };
            Timer counterTimer = new Timer(true);
            counterTimer.scheduleAtFixedRate(counterTimerTask, 0, 10 * 1000L);
        } catch (Exception e) {
            isRunning = false;
            LOGGER.error("Error in start method of startup Bean {}", e);
        } finally {
            LOGGER.info("Exiting start method {}", System.currentTimeMillis());
        }
    }

    // 对外提供获取最新结果的方法
    public Object getLatestSessionCount() {
        return latestSessionCountResult;
    }
}

2 Controller层实现

根据你的业务场景二选一即可:

场景1:前端主动轮询获取结果(实现最简单)

前端每10秒调用一次接口拉取最新数据即可:

@RestController
@RequestMapping("/session")
public class SessionCountController {
    @Autowired
    private StartupBean startupBean;

    // 手动触发定时任务的接口,不需要可以删掉
    @PostMapping("/startTask")
    public void startCountTask() throws Exception {
        startupBean.start();
    }

    // 获取最新统计结果
    @GetMapping("/count")
    public Object getLatestCount() {
        return startupBean.getLatestSessionCount();
    }
}

场景2:服务端主动推送结果(无需前端轮询)

用Spring原生支持的SSE实现服务端主动推送,前端建立一次连接就能持续收到最新结果:

@GetMapping(value = "/count/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamCountResult() {
    SseEmitter emitter = new SseEmitter();
    new Thread(() -> {
        try {
            while (true) {
                Object result = startupBean.getLatestSessionCount();
                if (result != null) {
                    emitter.send(result);
                }
                Thread.sleep(10000);
            }
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
    }).start();
    return emitter;
}

3 优化建议

  • 不推荐使用JDK原生Timer实现定时任务,单线程运行的特性会导致任务抛出异常后整个调度直接终止,建议替换为Spring自带的@Scheduled注解,开启@EnableScheduling后直接在方法上加@Scheduled(fixedRate = 10000)即可,无需手动管理调度线程生命周期。
  • 如果有存储历史结果、多节点共享结果的需求,可以把执行结果写入Redis或本地缓存,扩展能力更强。

内容的提问来源于stack exchange,提问作者vr3w3c9

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:36:04