依赖注入 - 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 官方更推荐 常见但略逊于构造函数注入
相关推荐
Tony Bai2 小时前
告别“If-Else”地狱:OpenFeature 如何重塑 Go 应用的特性开关管理?
开发语言·后端·golang
代码扳手2 小时前
一次线上事故后的反思:Go 项目中如何构建可靠的单元测试
后端·go
Cache技术分享2 小时前
276. Java Stream API - 使用 flatMap 和 mapMulti 清理数据并转换类型
前端·后端
狗头大军之江苏分军2 小时前
她在结婚那天离开了:我们该重新谈谈“结婚这件事”
前端·后端
上将邢道荣2 小时前
MCP学习笔记
后端
王中阳Go2 小时前
🚀 RAG 系统检索不准?是时候引入「离线精排」思维了!
后端·面试
雨中飘荡的记忆2 小时前
深入理解 Guava EventBus:让你的系统解耦更优雅
java·后端
武子康2 小时前
大数据-195 KNN/K近邻算法实战:欧氏距离+投票机制手写实现,含可视化与调参要点
大数据·后端·机器学习