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

多模块Spring应用中@Autowired注入失效问题求助

问题分析与解决方案

你的核心问题在于:手动new出来的策略类实例不在Spring容器的管理范围内,所以Spring不会处理这些实例中的@Autowired注解,导致依赖对象全部为null。同时,当前的GameStrategySelector实现需要手动维护策略列表,不符合开闭原则,我们可以通过Spring的特性来优化它。


一、解决@Autowired为null的问题

1. 让Spring管理所有策略类

确保所有实现BuildGameStrategy的类都被Spring识别为Bean,比如保持LocalPlayerGameStrategy上的@Component注解,MultiPlayerGameStrategy和ErrorGameTypeStrategy也需要添加@Component(如果它们有依赖的话):

@Component
public class MultiPlayerGameStrategy implements BuildGameStrategy {
    // 依赖注入和业务逻辑
}

@Component
public class ErrorGameTypeStrategy implements BuildGameStrategy {
    @Override
    public void buildGame(GameDto gameDto) {
        // 处理无效游戏类型的逻辑
    }

    @Override
    public boolean applies(GameDto gameDto) {
        return false; // 永远不会被过滤选中,作为默认兜底策略
    }
}

2. 让Spring自动注入策略列表

修改GameStrategySelector,不再手动new实例,而是通过构造注入让Spring自动收集所有BuildGameStrategy类型的Bean:

@Service
public class GameStrategySelector {
    private final List<BuildGameStrategy> strategyList;
    private final ErrorGameTypeStrategy errorStrategy;

    // 构造注入:Spring会自动把所有BuildGameStrategy类型的Bean注入到strategyList中
    public GameStrategySelector(List<BuildGameStrategy> strategyList, ErrorGameTypeStrategy errorStrategy) {
        this.strategyList = strategyList;
        this.errorStrategy = errorStrategy;
    }

    public BuildGameStrategy chooseStrategy(GameDto gameDto) {
        return strategyList
                .stream()
                .filter(strategy -> strategy.applies(gameDto))
                .findFirst()
                .orElse(errorStrategy); // 使用Spring管理的兜底策略,避免手动new
    }
}

3. 替换字段注入为构造注入(推荐)

Spring官方推荐使用构造注入而非字段注入,它能保证依赖在Bean实例化时就被注入,避免null风险,同时让Bean不可变、线程安全:

@Component
public class LocalPlayerGameStrategy implements BuildGameStrategy {
    private final GameService gameService;
    private final UserService userService;
    private final PlayerService playerService;

    // 构造注入所有依赖
    public LocalPlayerGameStrategy(GameService gameService, UserService userService, PlayerService playerService) {
        this.gameService = gameService;
        this.userService = userService;
        this.playerService = playerService;
    }

    // 业务方法实现不变
}

二、更优的StrategySelector实现思路

1. 利用自定义注解标记策略适用类型

我们可以给每个策略类添加自定义注解,明确它支持的游戏类型,避免在applies()方法中硬编码判断逻辑,同时让策略匹配更清晰:

第一步:定义自定义注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component // 让Spring自动扫描带此注解的类
public @interface GameStrategy {
    PlayerType[] supportedPlayerTypes();
}

第二步:给策略类添加注解

@GameStrategy(supportedPlayerTypes = PlayerType.LOCAL)
public class LocalPlayerGameStrategy implements BuildGameStrategy {
    // 依赖注入和业务逻辑

    @Override
    public boolean applies(GameDto gameDto) {
        // 通过注解信息判断匹配性,避免硬编码
        PlayerType[] supportedTypes = this.getClass().getAnnotation(GameStrategy.class).supportedPlayerTypes();
        return gameDto.getPlayers().stream()
                .allMatch(p -> Arrays.stream(supportedTypes)
                        .anyMatch(type -> type.name().equals(p.getPlayerType())));
    }
}

2. 策略优先级控制

如果存在多个策略可能匹配同一游戏类型,可以使用@Order注解指定优先级,Spring注入列表时会按顺序排列:

@Order(1) // 优先级更高,会被优先选中
@GameStrategy(supportedPlayerTypes = PlayerType.LOCAL)
public class LocalPlayerGameStrategy implements BuildGameStrategy {
    // ...
}

3. 简化主类注解

@SpringBootApplication已经包含了@Configuration、@EnableAutoConfiguration、@ComponentScan,所以你的主类可以简化:

@SpringBootApplication
@EnableMethodSecurity
@EntityScan(basePackages="com.rydzwr.tictactoe")
@EnableJpaRepositories(basePackages="com.rydzwr.tictactoe")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

如果database模块的包不在com.rydzwr.tictactoe下,需要把对应的包添加到@ComponentScan、@EntityScan、@EnableJpaRepositories的basePackages中,比如:

@ComponentScan(basePackages={"com.rydzwr.tictactoe", "com.rydzwr.database"})

内容的提问来源于stack exchange,提问作者Kacper Rydzyński

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:01:44