Spring WebSocket实现服务端主动推送倒计时数值至所有客户端
实现Spring Boot服务端主动推送倒计时至WebSocket客户端
问题根源
你遇到的空指针异常是因为Countdown不是Spring容器管理的Bean,无法自动注入SimpMessagingTemplate;同时在main方法中直接new线程的方式脱离了Spring上下文,导致依赖无法注入。
解决方案步骤
1. 将Countdown转为Spring管理的Bean并注入SimpMessagingTemplate
修改Countdown类,添加@Component注解,通过构造器注入SimpMessagingTemplate,并在倒计时逻辑中加入推送代码:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Component; @Component public class Countdown implements Runnable { private volatile int count = 0; private final SimpMessagingTemplate messagingTemplate; // 构造器注入SimpMessagingTemplate @Autowired public Countdown(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; } @Override public void run() { this.runTimer(); } public void runTimer() { count = 60; while (count > 0) { System.out.println("Countdown : " + count + " " + Thread.currentThread().getId()); try { count--; // 推送当前count值到所有订阅/topic/greetings的客户端 messagingTemplate.convertAndSend("/topic/greetings", new CountdownModel(count)); Thread.sleep(1000); } catch (Exception e) { System.out.println(e); } } } }
2. 调整线程启动方式,在Spring容器初始化后启动
不要在main方法中直接new线程,而是通过Spring的初始化回调确保线程在容器就绪后启动,比如实现ApplicationRunner接口:
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } // 容器初始化完成后启动倒计时线程 @Bean public ApplicationRunner countdownRunner(Countdown countdown) { return args -> { Thread th = new Thread(countdown); th.start(); }; } }
3. 确保CountdownModel可序列化
CountdownModel需要是标准POJO,提供getter方法以便客户端解析字段:
public class CountdownModel { private int count; public CountdownModel(int count) { this.count = count; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
4. 简化WebSocket控制器(可选)
如果不需要客户端触发推送的逻辑,控制器可简化为仅保留必要结构;若需客户端交互则保留原有方法:
import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.web.bind.annotation.RestController; @RestController public class CountdownWSController { private final SimpMessagingTemplate template; public CountdownWSController(SimpMessagingTemplate template) { this.template = template; } // 保留客户端触发的方法(若需要) // @MessageMapping("/client") // public void countDownService(int count) throws Exception{ // this.template.convertAndSend("/topic/greetings", new CountdownModel(count)); // } }
关键说明
- 让
Countdown成为Spring Bean后,Spring会自动注入SimpMessagingTemplate,彻底解决空指针问题。 - 使用
ApplicationRunner确保线程在Spring容器完全初始化后启动,此时所有依赖都已就绪。 volatile关键字保证count值的可见性,确保线程能读取到最新值;如果是多线程操作count,建议使用AtomicInteger保证原子性。
内容的提问来源于stack exchange,提问作者DKB
相关产品推荐
相关产品推荐

