IOC依赖注入问题:@Primary 和 @Qualifier的使用

假设现在有一个接口:

java 复制代码
public interface TestRepository {
    void save();
}

然后你写了两个实现类:

java 复制代码
@Repository
public class MysqlTestRepository implements TestRepository {

    @Override
    public void save() {
        System.out.println("保存到 MySQL");
    }
}

以及:

java 复制代码
@Repository
public class MemoryTestRepository implements TestRepository {

    @Override
    public void save() {
        System.out.println("保存到内存");
    }
}

此时 Spring 容器里实际上有两个 Bean:

java 复制代码
MysqlTestRepository
MemoryTestRepository

而且它们都属于:

java 复制代码
TestRepository

这时候如果你写:

java 复制代码
@Service
public class StudentService {

    private final TestRepository repository;

    public StudentService(TestRepository repository) {
        this.repository = repository;
    }
}

Spring 就懵了:

你要 TestRepository,但我这里有两个,到底给你哪个?

这时通常会启动失败。


1.@Primary:设置默认实现

你可以告诉 Spring:

如果有多个同类型 Bean,默认优先用这个。

例如:

java 复制代码
@Repository
@Primary
public class MysqlTestRepository implements TestRepository {

    @Override
    public void save() {
        System.out.println("保存到 MySQL");
    }
}

另一个:

java 复制代码
@Repository
public class MemoryTestRepository implements TestRepository {
}

那么:

java 复制代码
public StudentService(TestRepository repository)

Spring 会默认注入:

java 复制代码
MysqlTestRepository

因为它被标记了:

java 复制代码
@Primary

你可以理解成:

@Primary = 默认候选人。


2.@Qualifier:明确指定我要哪个

有时候不能只设置一个默认值。

比如:

java 复制代码
StudentService
→ 想用 MySQL

TestService
→ 想用 Memory

这时可以明确指定。

例如:

java 复制代码
@Service
public class StudentService {

    private final TestRepository repository;

    public StudentService(
            @Qualifier("mysqlTestRepository")
            TestRepository repository) {

        this.repository = repository;
    }
}

这表示:

我要名字叫 mysqlTestRepository 的那个 Bean。

Spring 默认会把:

复制代码
MysqlTestRepository

生成的 Bean 名字变成:

复制代码
mysqlTestRepository

也就是类名首字母小写。

3. 还可以自己指定 Bean 名字

比如:

java 复制代码
@Repository("mysqlRepo")
public class MysqlTestRepository
        implements TestRepository {
}

然后:

java 复制代码
public StudentService(
        @Qualifier("mysqlRepo")
        TestRepository repository) {
}

这样就不依赖默认的:

复制代码
mysqlTestRepository

名字了。

4.可以把 Spring 注入理解成一个匹配过程

Spring 创建:

复制代码
StudentService

发现构造器需要:

复制代码
TestRepository

于是去容器里找:

复制代码
有没有 TestRepository 类型的 Bean?

情况一:

复制代码
找到 0 个
→ 报错:没有 Bean

情况二:

复制代码
找到 1 个
→ 直接注入

情况三:

复制代码
找到 2 个或更多
→ 看有没有 @Qualifier
→ 没有就看有没有 @Primary
→ 还无法确定就报错

这套逻辑掌握以后,Spring 的依赖注入其实就很清楚了。

相关推荐
其实防守也摸鱼1 小时前
存储管理:页面置换算法学习任务(测验题要求给出置换页面顺序,缺页次数,缺页率)
android·前端·数据库·学习·oracle·自动化
mmsx2 小时前
Android 地图上绘制 KML:解析、样式与渲染
android·xml
运行时异常3 小时前
【无标题】
android
右手吉他3 小时前
高通平台IA APN问题分析之一
android·物联网
a5986524 小时前
Docker多开云手机,六边云独立端口隔离访问实战
android·运维·docker·容器·智能手机·云手机
峥嵘life4 小时前
Android16 开机后立即打开相机闪退问题分析与解决总结
android·开发语言·数码相机·策略模式
用户2018792831674 小时前
从点击图标到首帧"上菜":一篇吃透 Android 启动优化原理
android
镜象科技5 小时前
职业院校AI心理健康解决方案是什么?从一台设备到全周期守护
android·人工智能