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

Spring Boot如何实现单例常驻服务供全局共享访问

实现说明

你对Spring Bean生命周期的认知存在偏差:Spring 管理的 Bean 默认作用域为 singleton 单例,在整个应用上下文启动后仅会创建一个实例,实例内的字段状态会在应用运行期间一直留存,完全满足你「全局唯一常驻、跨请求共享状态、全应用可调用」的需求,不需要额外做自定义的单例管控。
你当前的代码没有被Spring容器托管,所以才会出现无法全局复用、状态不留存的问题,按以下步骤调整即可。

具体修改步骤
  • 给LimboQueueImpl类添加Spring业务组件注解,标记为被容器托管的Bean:
    @Service
    public class LimboQueueImpl implements LimboQueue {
      // 原有业务逻辑无需改动
      private ConcurrentLinkedQueue<Long> queue = new ConcurrentLinkedQueue<Long>();
    
      private int numberCounter = 0;
    
      @Override
      public String getCurrentUser() {
        return null;
      }
    
      @Override
      public boolean addPetition(Long userId) throws UserNotFoundException {
        int ticketNumber = this.addNumber();
        // TODO: save ticket
        return this.queue.add(userId);
      }
    
      @Override
      public Long getNextPetition() {
        return this.queue.isEmpty() ? null : this.queue.remove();
      }
    
      @Override
      public boolean deletePetition(Long userId) {
        return this.queue.remove(userId);
      }
    
      private synchronized int addNumber() {
        return this.numberCounter++;
      }
    
      private synchronized void resetNumberCounter() {
        this.numberCounter = 0;
      }
    }
    
  • 所有需要调用该服务的位置(Controller、其他业务Service类)禁止手动new LimboQueueImpl()创建实例,统一通过Spring依赖注入获取实例,推荐使用构造器注入,示例:
    @RestController
    @RequestMapping("/petitions")
    public class PetitionController {
      private final LimboQueue limboQueue;
    
      // Spring 4.3及以上版本,单构造器场景无需额外添加@Autowired注解
      public PetitionController(LimboQueue limboQueue) {
        this.limboQueue = limboQueue;
      }
    
      @PostMapping
      public ResponseEntity<Boolean> add(@RequestParam Long userId) throws UserNotFoundException {
        return ResponseEntity.ok(limboQueue.addPetition(userId));
      }
    
      @GetMapping("/next")
      public ResponseEntity<Long> getNext() {
        return ResponseEntity.ok(limboQueue.getNextPetition());
      }
    }
    
并发优化建议

你当前代码的并发控制逻辑基本可用,有两处可以优化的点:

  • ConcurrentLinkedQueue本身是线程安全的无界队列,自带的增、删、判空方法都保证原子性,不需要额外加同步控制。
  • 计数器numberCounter当前用synchronized修饰操作方法可以保证线程安全,更轻量的实现是替换为AtomicInteger,省去手动加锁的开销:
    // 替换原int类型计数器定义
    private final AtomicInteger numberCounter = new AtomicInteger(0);
    
    private int addNumber() {
      return numberCounter.incrementAndGet();
    }
    
    private void resetNumberCounter() {
      numberCounter.set(0);
    }
    

注意:这种内存存储状态的方式仅适用于单实例部署场景。如果后续应用做集群多实例部署,每个应用实例会持有独立的队列和计数器,多实例间状态不互通,这种场景需要将共享状态下沉到Redis等集中式存储组件保证全局一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:15:41