依赖注入 - Spring 在 IoC 容器里查找一个 Bean 的不同方式示例

通过写一个完整的 Spring 示例 ,展示同时存在两个实现类时,如何用 @Resource@Qualifier 精确选择注入。

现有代码

  1. 定义接口
java 复制代码
public interface Processor {
    void process();
}
  1. 两个实现类
java 复制代码
import org.springframework.stereotype.Component;

@Component("creditCardProcessor")
public class CreditCardProcessor implements Processor {
    @Override
    public void process() {
        System.out.println("Processing credit card...");
    }
}

@Component("zhiFuBaoProcessor")
public class ZhiFuBaoProcessor implements Processor {
    @Override
    public void process() {
        System.out.println("Processing zhifubao...");
    }
}

第一种:使用 @Resource 指定注入(最常见)

java 复制代码
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class PaymentService1 {

    // 按名字注入,必须和 Bean 名字一致
    @Resource(name="creditCardProcessor")
    private Processor processor;

    public void pay() {
        processor.process();
    }
}

第二种:使用构造函数注入 + @Qualifier(Spring 官方推荐)

java 复制代码
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class PaymentService2 {
    private final Processor processor;

    // 构造函数注入,指定要注入的 Bean
    public PaymentService2(@Qualifier("creditCardProcessor") Processor processor) {
        this.processor = processor;
    }
    
    public void pay() {
        processor.process();
    }
}

容器里只有一个 Processor 类型的 Bean(比如只有 CreditCardProcessor),Spring 会直接注入它,不需要 @Qualifier

第三种:使用 @Autowired + @Qualifier 指定注入

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class PaymentService3 {

    @Autowired
    @Qualifier("zhiFuBaoProcessor")
    private Processor processor;

    public void pay() {
        processor.process();
    }
}

测试运行

java 复制代码
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    CommandLineRunner run(PaymentService1 paymentService1, PaymentService2 paymentService2, PaymentService3 paymentService3) {
        return args -> {
            paymentService1.pay();   // 输出:Processing credit card...
            paymentService2.pay();  // 输出:Processing credit card...
            paymentService3.pay();  // 输出:Processing zhifubao...
        };
    }
}

IoC 的好处

Spring IoC 容器的一个好处:调用方不需要修改,只要容器负责把合适的依赖注入进去

字段注入和构造函数注入的共同点:

  • 解耦调用方 :调用 PaymentService 的地方不需要关心具体用的是 CreditCardProcessor 还是 ZhiFuBaoProcessor
  • 切换实现简单:只要改 Bean 配置或注解,调用代码完全不用动。
  • 由 IoC 容器负责依赖管理:容器在启动时扫描、创建 Bean,并根据注解或配置自动注入。

字段注入和构造函数注入的区别:

特性 构造函数注入 @Resource 字段注入
注入时机 对象创建时必须提供依赖 对象创建后由容器反射赋值
空值风险 无,构造函数强制依赖 有可能出现 null(如果容器没找到匹配 Bean)
测试友好性 更方便单元测试(直接传 mock) 测试时需要容器或反射赋值
推荐程度 Spring 官方更推荐 常见但略逊于构造函数注入
相关推荐
IT_陈寒2 小时前
SpringBoot实战:3个隐藏技巧让你的应用性能飙升50%
前端·人工智能·后端
彭于晏Yan3 小时前
MQTT消息服务
spring boot·后端·中间件
程序员Sunday3 小时前
Claude Code 生态爆发:5个必知的新工具
前端·人工智能·后端
weixin_387534223 小时前
Ownership - Rust Hardcore Head to Toe
开发语言·后端·算法·rust
前端付豪3 小时前
实现一个用户可以有多个会话
前端·后端·llm
若水不如远方4 小时前
分布式一致性(六):拥抱可用性 —— 最终一致性与 Gossip 协议
分布式·后端·算法
lianghanwu19994 小时前
深入解析 Apache Kafka:从核心原理到实战进阶指南
后端
想不到一个好的ID4 小时前
Claude Code 初学者必看指南
前端·后端
我爱娃哈哈4 小时前
SpringBoot + Redis Stream + 消费组:替代 Kafka 轻量级消息队列,低延迟高吞吐
后端
程序员大飞哥4 小时前
MPTCP 协议全景:从 RFC 6824 到 RFC 8684 的演进
后端