依赖注入 - 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 官方更推荐 常见但略逊于构造函数注入
相关推荐
枕星而眠几秒前
C++ String类精讲:从基础用法到进阶底层原理
开发语言·c++·后端·学习方法
念何架构之路6 分钟前
Go pprof性能剖析
开发语言·后端·golang
zhz52146 分钟前
Spring Boot 接入国密实战:传输加密(TLCP)+ 密码加密(SM4)
java·spring boot·后端·国密·sm4
我是一颗柠檬14 分钟前
【JDK8新特性】函数式接口Day2
java·开发语言·后端·intellij-idea
Trouvaille ~14 分钟前
【Redis篇】Redis 安装与启动:快速搭建一个 Redis 环境
数据库·redis·后端·ubuntu·缓存·环境搭建·安装教程
Mahir0817 分钟前
Spring Boot 自动装配深度解密:从原理到自定义 Starter 实战
java·spring boot·后端·自动装配·自定义starter·大厂面试题
Mahir089 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
IT_陈寒13 小时前
Redis缓存击穿把我整不会了,原来还有这手操作
前端·人工智能·后端
kyriewen14 小时前
面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了
后端·mysql·面试
文心快码BaiduComate14 小时前
干货|Comate Harness Engineering工程实践指南
前端·后端·程序员