mcpField
S
spring-boot-dependency-injection

spring-boot-dependency-injection

github.com/giuseppe-trisciuoglio开发3653.8k 次安装7 周前更新
代码仓库

关于 spring-boot-dependency-injection

面向 Spring Boot 开发者的依赖注入技能,侧重构造器注入和明确的 Bean 装配。还介绍通过独立单元测试与最小上下文测试及早发现装配问题。

主要功能

  1. 01必需依赖使用构造器注入
  2. 02明确处理可选协作者
  3. 03使用 @Primary 和 @Qualifier 选择 Bean
  4. 04在配置类中装配对象
  5. 05最小上下文与构造器测试

适用场景

  1. 01创建 Spring 服务与组件
  2. 02替换旧代码中的字段注入
  3. 03选择同类型的多个 Bean
  4. 04在完整集成前验证装配

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill spring-boot-dependency-injection

安装后在 Claude Code 中输入/spring-boot-dependency-injection确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
examples.md
reference.md
spring-official-dependency-injection.md

详细介绍

Spring Boot 依赖注入

概述

为 Spring Boot 提供以构造函数优先的依赖注入模式:

  • 通过构造函数注入必需的协作者
  • 通过 ObjectProvider 或空操作回退方案处理可选协作者
  • 通过 @Primary 和 @Qualifier 选择 Bean
  • 在完整集成前,通过最小化上下文测试进行验证

适用场景

在以下情况下使用此技能:

  • 创建新的 @Service、@Component、@Repository 或 @Configuration 类
  • 替换遗留 Spring 代码中的字段注入
  • 使用限定符或主 Bean 解决同一类型存在多个 Bean 的问题
  • 处理可选功能、适配器或集成,避免依赖 null 进行装配
  • 检查循环依赖或脆弱的上下文启动故障
  • 为直接通过构造函数进行单元测试做好代码准备

指南

1. 区分必需和可选协作者

对于每个类,明确以下内容:

  • 正常运行所必需的协作者
  • 用于启用集成、缓存、通知或特性开关行为的可选协作者

必需的协作者应放在构造函数中。可选协作者需要采用明确的策略,例如 ObjectProvider、条件 Bean 或空操作实现。

2. 默认使用构造函数注入

对于应用服务和适配器:

  • 通过构造函数注入必需依赖
  • 将注入的字段设为 final
  • 在单元测试中直接实例化类,无需启动 Spring

通常只需一个构造函数;这种情况下不需要 @Autowired。

3. 有意处理可选行为

合适的选项包括:

  • 在延迟访问有用时使用 ObjectProvider<T>
  • 在装配应随配置变化时使用 @ConditionalOnProperty 或 @ConditionalOnMissingBean
  • 在调用方无需关心功能是否启用时使用空操作实现

避免使用可为 null 的协作者,以免运行时行为变得模糊。

4. 仅在必要时使用 Bean 选择注解

当多个 Bean 具有相同类型时:

  • 使用 @Primary 指定默认实现
  • 使用 @Qualifier 指定命名变体
  • 保持限定符名称稳定且易于搜索

如果选择规则变得复杂,请将其移到专用配置类中,而不是分散到各个服务里。

5. 将装配逻辑放在配置中,而非业务代码中

在以下情况下使用 @Configuration 和 @Bean 方法:

  • 对象来自第三方库
  • 需要条件创建逻辑
  • 需要特定于环境的装配或显式组合

业务服务不应了解基础设施协作者的实例化方式。

6. 显式验证装配

编写新的服务或配置后:

  1. 使用最小化上下文测试验证 Bean 是否加载:
    @SpringBootTest
    @ContextConfiguration(classes = UserService.class)
    class UserServiceWiringTest {
        @Autowired UserService userService;
        @Test void serviceIsInstantiated() { assertNotNull(userService); }
    }
    
  2. 运行基于构造函数的单元测试,验证服务行为(无需 Spring)。
  3. 仅在必须验证 MVC、JPA 或消息传递集成时,添加切片测试。
  4. 将 @SpringBootTest 留作容器级装配验证之用。

第 1 步出现故障,说明在添加业务逻辑前就存在装配问题。

示例

示例 1:构造函数优先的应用服务
@Service
public class UserService {

    private final UserRepository userRepository;
    private final EmailSender emailSender;

    public UserService(UserRepository userRepository, EmailSender emailSender) {
        this.userRepository = userRepository;
        this.emailSender = emailSender;
    }

    public User register(UserRegistrationRequest request) {
        User user = userRepository.save(User.from(request));
        emailSender.sendWelcome(user);
        return user;
    }
}

此类便于在单元测试中直接使用模拟对象进行实例化。

示例 2:带空操作回退方案的可选依赖
@Service
public class ReportService {

    private final ReportRepository reportRepository;
    private final NotificationGateway notificationGateway;

    public ReportService(
        ReportRepository reportRepository,
        ObjectProvider<NotificationGateway> notificationGatewayProvider
    ) {
        this.reportRepository = reportRepository;
        this.notificationGateway = notificationGatewayProvider.getIfAvailable(NotificationGateway::noOp);
    }
}

这样可以明确表达可选行为,同时避免在类的其余部分传播 null 处理逻辑。

示例 3:通过明确规则选择多个 Bean
@Configuration
public class PaymentConfiguration {

    @Bean
    @Primary
    PaymentGateway stripeGateway() {
        return new StripePaymentGateway();
    }

    @Bean
    @Qualifier("fallbackGateway")
    PaymentGateway mockGateway() {
        return new MockPaymentGateway();
    }
}

使用 @Primary 作为默认路径,仅在需要特定变体时使用 @Qualifier。

最佳实践

  • 对必需依赖,优先使用构造器注入。
  • 保持服务构造器简洁;如果一个类需要太多协作者,说明设计可能需要引入另一个抽象。
  • 使用无操作或条件 Bean,而不是可空的可选依赖。
  • 将特定于框架的创建逻辑放在配置类中。
  • 先在没有 Spring 的情况下测试服务,仅在能带来价值时再添加容器测试。
  • 重构时移除字段注入,而不是继续扩展它。

限制和警告

  • 字段注入会隐藏依赖,使测试更难编写。
  • 循环依赖通常是设计问题,不是用 @Lazy 解决的布线技巧。
  • 过度使用限定符会让代码库难以理解;优先采用更好的抽象或更清晰的配置。
  • 可选协作者在缺失时仍需有确定的行为。
  • 如果过早使用完整上下文测试,可能会掩盖布线失败的真正原因。

参考资料

  • references/reference.md
  • references/examples.md
  • references/spring-official-dependency-injection.md

相关技能

  • spring-boot-crud-patterns
  • spring-boot-rest-api-standards
  • unit-test-service-layer

评论

支持 Markdown