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

如何让实现Runnable的类成为可动态创建Bean的Spring Boot组件

解决方案:让Spring动态构造注入GameSessionRunner实例

问题背景

需要实现一个GameSessionRunner组件(实现Runnable接口),它的实例依赖REST请求中动态生成的SudokuGame对象。当前代码直接用new创建GameSessionRunner,希望改为由Spring通过构造注入SudokuGame生成实例,后续封装成GameSession存入仓库。

具体实现步骤

1. 调整GameSessionRunner的注解与构造方法

将GameSessionRunner标记为Spring组件,并设置为原型作用域(保证每次请求生成新实例),同时通过构造方法注入所有依赖:动态生成的SudokuGame和Spring管理的NotificationService。

修改后的GameSessionRunner:

@Component
@Scope("prototype") // 每次调用都生成新实例
public class GameSessionRunner implements Runnable {

    private final SudokuGame game;
    private boolean isStopped;
    private boolean isPaused;

    private final NotificationService notificationService;

    // 构造注入所有依赖:动态传入的SudokuGame + Spring托管的NotificationService
    public GameSessionRunner(SudokuGame game, NotificationService notificationService) {
        this.game = game;
        this.notificationService = notificationService;
    }

    @Override
    public void run() {
        // 业务逻辑实现
    }

    public void pauseGame() {
        // 暂停逻辑实现
    }

    public void resumeGame() {
        // 恢复逻辑实现
    }

    public void stopGame() {
        // 停止逻辑实现
    }
}

2. 在GameController中获取Spring托管的GameSessionRunner实例

由于GameSessionRunner是原型作用域,不能直接用@Autowired(仅会注入一次),需借助ObjectFactory获取新实例并传入动态生成的SudokuGame。

修改后的GameController:

@RestController
@RequestMapping("game-server")
public class GameController {

    private final GameService gameService;
    private final GameSessionRepository gameSessionRepository;
    private final ObjectFactory<GameSessionRunner> gameSessionRunnerFactory;

    // 构造注入所需组件,包括用于获取原型实例的ObjectFactory
    public GameController(GameService gameService, 
                          GameSessionRepository gameSessionRepository,
                          ObjectFactory<GameSessionRunner> gameSessionRunnerFactory) {
        this.gameService = gameService;
        this.gameSessionRepository = gameSessionRepository;
        this.gameSessionRunnerFactory = gameSessionRunnerFactory;
    }

    @CrossOrigin(origins = "*")
    @PostMapping("/create-game")
    public ResponseEntity<SudokuGame> createGame(@RequestBody CreateGameRequest createGameRequest) {
        SudokuGame game = gameService.createGame(createGameRequest);
        
        // 通过ObjectFactory获取Spring托管的GameSessionRunner实例,传入动态生成的game
        GameSessionRunner gameSessionRunner = gameSessionRunnerFactory.getObject(game);
        
        Thread gameThread = new Thread(gameSessionRunner);
        GameSession gameSession = new GameSession(gameSessionRunner, gameThread);

        gameSessionRepository.addGameSession(game.getGameId(), gameSession);
        gameThread.start(); // 启动线程执行run方法

        return new ResponseEntity<>(game, HttpStatus.CREATED);
    }
}

3. 补充说明

  • 原型作用域的必要性:每个游戏会话对应唯一的SudokuGame,因此GameSessionRunner必须设为原型作用域,确保每次请求生成独立实例。
  • ObjectFactory的作用:自动处理Spring托管依赖的注入(如NotificationService),同时支持传入动态参数(SudokuGame)。
  • 线程启动:必须调用gameThread.start(),否则run()方法不会执行。

4. 其他类保持不变

GameSession和GameSessionRepository无需修改,维持原有逻辑即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:20:19