spring-boot-dependency-injection

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Spring Boot Dependency Injection

Spring Boot 依赖注入

This skill captures the dependency injection approach promoted in this repository: constructor-first design, explicit optional collaborators, and deterministic configuration that keeps services testable and framework-agnostic.
本技能涵盖了本仓库所推崇的依赖注入方法:构造函数优先设计、显式声明可选协作者,以及确保服务可测试且与框架无关的确定性配置。

Overview

概述

  • Prioritize constructor injection to keep dependencies explicit, immutable, and mockable.
  • Treat optional collaborators through guarded setters or providers while documenting defaults.
  • Resolve bean ambiguity intentionally through qualifiers, primary beans, and profiles.
  • Validate wiring with focused unit tests before relying on Spring's TestContext framework.
  • 优先使用构造函数注入,确保依赖关系清晰、不可变且可模拟。
  • 通过受保护的setter方法或提供者来处理可选协作者,同时记录默认行为。
  • 通过限定符、主Bean和配置文件来主动解决Bean歧义问题。
  • 在依赖Spring的TestContext框架之前,先通过针对性的单元测试验证依赖装配。

When to Use

适用场景

  • Implement constructor injection for new
    @Service
    ,
    @Component
    , or
    @Repository
    classes.
  • Replace legacy field injection while modernizing Spring modules.
  • Configure optional or pluggable collaborators (feature flags, multi-tenant adapters).
  • Audit bean definitions before adding integration tests or migrating Spring Boot versions.
  • 为新的
    @Service
    @Component
    @Repository
    类实现构造函数注入。
  • 在现代化Spring模块时,替换传统的字段注入方式。
  • 配置可选或可插拔的协作者(如功能标志、多租户适配器)。
  • 在添加集成测试或迁移Spring Boot版本之前,审核Bean定义。

Prerequisites

前置条件

  • Align project with Java 17+ and Spring Boot 3.5.x (or later) to leverage records and
    @ServiceConnection
    .
  • Keep build tooling ready to run
    ./gradlew test
    or
    mvn test
    for validation.
  • Load supporting material from
    ./references/
    when deeper patterns or samples are required.
  • 项目需适配Java 17+及Spring Boot 3.5.x(或更高版本),以使用records和
    @ServiceConnection
    特性。
  • 准备好构建工具,以便运行
    ./gradlew test
    mvn test
    进行验证。
  • 当需要深入了解模式或示例时,从
    ./references/
    加载相关参考资料。

Workflow

工作流

1. Map Collaborators

1. 梳理协作者

  • Inventory constructors,
    @Autowired
    members, and configuration classes.
  • Classify dependencies as mandatory (must exist) or optional (feature-flagged, environment-specific).
  • 盘点构造函数、
    @Autowired
    成员及配置类。
  • 将依赖分为必填项(必须存在)和可选项(功能标志控制、特定环境)。

2. Apply Constructor Injection

2. 应用构造函数注入

  • Introduce constructors (or Lombok
    @RequiredArgsConstructor
    ) that accept every mandatory collaborator.
  • Mark injected fields
    final
    and protect invariants with
    Objects.requireNonNull
    if Lombok is not used.
  • Update
    @Configuration
    or
    @Bean
    factories to pass dependencies explicitly; consult
    ./references/reference.md
    for canonical bean wiring.
  • 添加接收所有必填协作者的构造函数(或使用Lombok的
    @RequiredArgsConstructor
    )。
  • 如果不使用Lombok,将注入字段标记为
    final
    ,并使用
    Objects.requireNonNull
    确保不变性。
  • 更新
    @Configuration
    @Bean
    工厂类,显式传递依赖;如需标准Bean装配方式,请参考
    ./references/reference.md

3. Handle Optional Collaborators

3. 处理可选协作者

  • Supply setters annotated with
    @Autowired(required = false)
    or inject
    ObjectProvider<T>
    for lazy access.
  • Provide deterministic defaults (for example, no-op implementations) and document them inside configuration modules.
  • Follow
    ./references/examples.md#example-2-setter-injection-for-optional-dependencies
    for a full workflow.
  • 提供标注有
    @Autowired(required = false)
    的setter方法,或注入
    ObjectProvider<T>
    以实现延迟访问。
  • 提供确定性的默认实现(比如空操作实现),并在配置模块中记录这些默认行为。
  • 完整工作流可参考
    ./references/examples.md#example-2-setter-injection-for-optional-dependencies

4. Resolve Bean Selection

4. 解决Bean选择歧义

  • Choose
    @Primary
    for dominant implementations and
    @Qualifier
    for niche variants.
  • Use profiles, conditional annotations, or factory methods to isolate environment-specific wiring.
  • Reference
    ./references/reference.md#conditional-bean-registration
    for conditional and profile-based samples.
  • 为主要实现类使用
    @Primary
    ,为特定变体使用
    @Qualifier
  • 使用配置文件、条件注解或工厂方法来隔离特定环境的依赖装配。
  • 条件装配和基于配置文件的示例可参考
    ./references/reference.md#conditional-bean-registration

5. Validate Wiring

5. 验证依赖装配

  • Write unit tests that instantiate classes manually with mocks to prove Spring-free testability.
  • Add slice or integration tests (
    @WebMvcTest
    ,
    @DataJpaTest
    ,
    @SpringBootTest
    ) only after constructor contracts are validated.
  • Reuse patterns in
    ./references/reference.md#testing-with-dependency-injection
    to select the proper test style.
  • 编写单元测试,手动使用模拟对象实例化类,证明无需Spring即可测试。
  • 仅在构造函数契约验证通过后,再添加切片测试或集成测试(
    @WebMvcTest
    @DataJpaTest
    @SpringBootTest
    )。
  • 可复用
    ./references/reference.md#testing-with-dependency-injection
    中的模式来选择合适的测试方式。

Examples

示例

Basic Constructor Injection

基础构造函数注入

java
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;

    public User register(UserRegistrationRequest request) {
        User user = User.create(request.email(), request.name());
        userRepository.save(user);
        emailService.sendWelcome(user);
        return user;
    }
}
  • Instantiate directly in tests:
    new UserService(mockRepo, mockEmailService);
    with no Spring context required.
java
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;

    public User register(UserRegistrationRequest request) {
        User user = User.create(request.email(), request.name());
        userRepository.save(user);
        emailService.sendWelcome(user);
        return user;
    }
}
  • 可在测试中直接实例化:
    new UserService(mockRepo, mockEmailService);
    ,无需Spring上下文。

Intermediate: Optional Dependency with Guarded Setter

进阶:带保护Setter的可选依赖

java
@Service
public class ReportService {
    private final ReportRepository reportRepository;
    private CacheService cacheService = CacheService.noOp();

    public ReportService(ReportRepository reportRepository) {
        this.reportRepository = reportRepository;
    }

    @Autowired(required = false)
    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }
}
  • Provide fallbacks such as
    CacheService.noOp()
    to ensure deterministic behavior when the optional bean is absent.
java
@Service
public class ReportService {
    private final ReportRepository reportRepository;
    private CacheService cacheService = CacheService.noOp();

    public ReportService(ReportRepository reportRepository) {
        this.reportRepository = reportRepository;
    }

    @Autowired(required = false)
    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }
}
  • 提供
    CacheService.noOp()
    这类回退实现,确保当可选Bean不存在时行为是确定的。

Advanced: Conditional Configuration Across Modules

高级:跨模块条件配置

java
@Configuration
@Import(DatabaseConfig.class)
public class MessagingConfig {

    @Bean
    @ConditionalOnProperty(name = "feature.notifications.enabled", havingValue = "true")
    public NotificationService emailNotificationService(JavaMailSender sender) {
        return new EmailNotificationService(sender);
    }

    @Bean
    @ConditionalOnMissingBean(NotificationService.class)
    public NotificationService noopNotificationService() {
        return NotificationService.noOp();
    }
}
  • Combine
    @Import
    , profiles, and conditional annotations to orchestrate cross-cutting modules.
Additional worked examples (including tests and configuration wiring) are available in
./references/examples.md
.
java
@Configuration
@Import(DatabaseConfig.class)
public class MessagingConfig {

    @Bean
    @ConditionalOnProperty(name = "feature.notifications.enabled", havingValue = "true")
    public NotificationService emailNotificationService(JavaMailSender sender) {
        return new EmailNotificationService(sender);
    }

    @Bean
    @ConditionalOnMissingBean(NotificationService.class)
    public NotificationService noopNotificationService() {
        return NotificationService.noOp();
    }
}
  • 结合
    @Import
    、配置文件和条件注解来协调跨模块的配置。
更多完整示例(包括测试和配置装配)可查看
./references/examples.md

Best Practices

最佳实践

  • Prefer constructor injection for mandatory dependencies; allow Spring 4.3+ to infer
    @Autowired
    on single constructors.
  • Encapsulate optional behavior inside dedicated adapters or providers instead of accepting
    null
    pointers.
  • Keep service constructors lightweight; extract orchestrators when dependency counts exceed four.
  • Favor domain interfaces in the domain layer and defer framework imports to infrastructure adapters.
  • Document bean names and qualifiers in shared constants to avoid typo-driven mismatches.
  • 必填依赖优先使用构造函数注入;Spring 4.3+版本可自动推断单个构造函数的
    @Autowired
    注解。
  • 将可选行为封装在专用适配器或提供者中,而非接受
    null
    指针。
  • 保持服务构造函数简洁;当依赖数量超过四个时,提取协调器。
  • 领域层优先使用领域接口,将框架导入延迟到基础设施适配器中。
  • 将Bean名称和限定符记录在共享常量中,避免因拼写错误导致的不匹配。

Constraints

约束条件

  • Avoid field injection and service locator patterns because they obscure dependencies and impede unit testing.
  • Prevent circular dependencies by publishing domain events or extracting shared abstractions.
  • Limit
    @Lazy
    usage to performance-sensitive paths and record the deferred initialization risk.
  • Do not add profile-specific beans without matching integration tests that activate the profile.
  • Ensure each optional collaborator has a deterministic default or feature-flag handling path.
  • 避免使用字段注入和服务定位器模式,因为它们会模糊依赖关系并阻碍单元测试。
  • 通过发布领域事件或提取共享抽象来避免循环依赖。
  • 仅在性能敏感路径中使用
    @Lazy
    ,并记录延迟初始化的风险。
  • 不要添加特定配置文件的Bean,除非有对应的激活该配置文件的集成测试。
  • 确保每个可选协作者都有确定性的默认实现或功能标志处理路径。

Reference Materials

参考资料

  • extended documentation covering annotations, bean scopes, testing, and anti-pattern mitigations
  • progressive examples from constructor injection basics to multi-module configurations
  • curated excerpts from the official Spring Framework documentation (constructor vs setter guidance, conditional wiring)
  • 涵盖注解、Bean作用域、测试及反模式缓解的扩展文档
  • 从构造函数注入基础到多模块配置的进阶示例
  • 官方Spring Framework文档精选片段(构造函数与setter注入指南、条件装配)

Related Skills

相关技能

  • spring-boot-crud-patterns
    – service-layer orchestration patterns that rely on constructor injection.
  • spring-boot-rest-api-standards
    – controller-layer practices that assume explicit dependency wiring.
  • unit-test-service-layer
    – Mockito-based testing patterns for constructor-injected services.
  • spring-boot-crud-patterns
    —— 依赖构造函数注入的服务层编排模式。
  • spring-boot-rest-api-standards
    —— 基于显式依赖装配的控制器层实践。
  • unit-test-service-layer
    —— 针对构造函数注入服务的Mockito测试模式。