从零开始 Spring Boot 43:DI 注解

news/2024/11/13 3:46:22/

从零开始 Spring Boot 43:DI 注解

spring boot

图源:简书 (jianshu.com)

Spring 通过注解实现 DI(依赖注入),本文详细讨论这些注解。

@Autowired

@Autowired是 Spring 定义的注解,属于包org.springframework.beans.factory.annotation

@Autowired匹配 bean 的顺序是:

  1. 按类型(type)匹配
  2. 按限定符(qualifier)匹配
  3. 按名称(name)匹配

@Autowired是最常用的注解,用它可以通过属性注入、Setter注入、构造器注入来实现DI。在前文中讨论过这些内容,这里不再重复。

筛选备选项

一般来说,用@Autowired注入时必须存在类型匹配的唯一的 bean,没有匹配到和匹配到一个以上的 bean 都会报错:

@ToString
@EqualsAndHashCode
public abstract class Carrier {protected final String maker;protected final String model;protected Carrier(String maker, String model) {this.maker = maker;this.model = model;}
}@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Car extends Carrier {public Car(final String maker, final String model) {super(maker, model);}
}@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Motorcycle extends Carrier {public Motorcycle(final String maker, final String model) {super(maker, model);}
}@Service
public class CarrierService {@Autowiredprivate Carrier defaultCarrier;public Carrier getDefaultCarrier() {return defaultCarrier;}
}@Configuration
public class WebConfig {@Lazy@Autowiredprivate CarrierService carrierService;@BeanCar defaultCar(){return new Car("长安汽车","X5");}@BeanMotorcycle defaultMotorcycle(){return new Motorcycle("哈雷","A7");}@BeanApplicationRunner applicationRunner(){return args -> {Carrier defaultCarrier = carrierService.getDefaultCarrier();System.out.println(defaultCarrier);};}
}

这里定义的两个 bean 都具备Carrier类型,因此用@Autowired注入Carrier defaultCarrier属性时会报错,Spring 不知道要注入的是哪一个。

可以通过@Qualifier缩小筛选范围:

@Service
public class CarrierService {@Autowired@Qualifier("defaultCar")private Carrier defaultCarrier;// ...
}

示例中使用@Qualifier("defaultCar")将注入限定为名称为defaultCar的 bean,因此可以正常注入。

除了使用限定符,还可以使用名称进行筛选,@Autowired使用属性名作为 bean 名称进行匹配:

@Service
public class CarrierService {@Autowiredprivate Carrier defaultCar;// ...
}

在用于名称匹配时,@Autowired并不好用,因为它只能用属性名作为 bean 名称匹配,@Resource则可以用name属性指定 bean 名称,而@inject可以使用@Named注解指定 bean 名称。

@Qualifier还可以更灵活地对 bean 进行筛选,详细内容可以阅读我的另一篇文章。

除了@Qualifier,还可以使用@Primary指定一个主要的 bean 作为有多个备选项时的首选注入,详细情况可以参考我的同一篇文章。

@Resource

@Resource是 Java 扩展包的注解,属于包javax.annotation.Resource

@Autowired按照类型优先进行匹配,@Resource按照名称优先进行匹配,其匹配顺序是:

  1. 按名称(name)匹配
  2. 按类型(type)匹配
  3. 按限定符(qualifier)匹配

修改之前的示例,使用@Resource进行依赖注入:

@Service
public class CarrierService {@Resourceprivate Carrier defaultCarrier;// ...
}

会报错,因为不能按照defaultCarrier找到 bean,如果按照类型Carrier匹配,能匹配到2个。

可以通过@Resourcename属性指定要匹配的 bean 名称:

@Service
public class CarrierService {@Resource(name = "defaultCar")private Carrier defaultCarrier;// ...
}

或者也可以修改属性名称:

@Service
public class CarrierService {@Resourceprivate Carrier defaultCar;public Carrier getDefaultCarrier() {return defaultCar;}
}

或者按照类型匹配,提供一个唯一 bean 对应的类型:

@Service
public class CarrierService {@Resourceprivate Car defaultCarrier;// ...
}

最后,同样可以使用@Qualifier

@Service
public class CarrierService {@Resource@Qualifier("defaultCar")private Carrier defaultCarrier;// ...
}

@Resource还可以通过 Setter 注入,用法与属性注入一致,这里不再说明。

@Inject

@Inject同样属于 Java 扩展包,属于包javax.inject.Inject

@Inject的匹配顺序是:

  1. 按类型匹配
  2. 按限定符匹配
  3. 按名称匹配

要使用@Inject注解要先添加依赖:

<dependency><groupId>jakarta.inject</groupId><artifactId>jakarta.inject-api</artifactId><version>2.0.1</version>
</dependency>

先看按类型匹配的示例:

@Service
public class CarrierService {@Injectprivate Car defaultCarrier;// ...
}

如果按类型匹配出多个候选项,可以通过限定符进一步匹配:

@Service
public class CarrierService {@Inject@Qualifier("defaultCar")private Carrier defaultCarrier;// ...
}

也可以通过名称进一步匹配:

@Service
public class CarrierService {@Inject@Named("defaultMotorcycle")private Carrier defaultCarrier;// ...
}

@Named同样属于 Java 扩展包,属于包jakarta.inject.Named

如果@Named注解没有起作用,可以检查一下 maven 依赖中的jakarta.inject模块的版本是否正确。

@Inject用于 Setter 注入的方式与属性注入类似,这里不再赘述。

@Inject也可以用于构造器注入:

@Service
public class CarrierService {private Carrier defaultCarrier;@Injectpublic CarrierService(@Named("defaultCar") Carrier defaultCarrier) {this.defaultCarrier = defaultCarrier;}// ...
}

总结

如果需要按照类型优先匹配,可以使用@Autowired@inject,如果需要按照 bean 名称优先匹配,可以使用@Resource

参考资料

  • 从零开始 Spring Boot 27:IoC - 红茶的个人站点 (icexmoon.cn)
  • Using JSR 330 Standard Annotations :: Spring Framework
  • Wiring in Spring: @Autowired, @Resource and @Inject | Baeldung

http://www.ppmy.cn/news/461833.html

相关文章

Vb+access学生公寓管理系统(论文+系统)

随着电脑的普及与使用,现在的管理也提升了一个档次,渐渐实现了无纸化办公,即从原来的人工记录管理模式转变为电脑一体化管理。高校是科研的阵地,后勤的公寓管理也应该一改传统的人工管理,更加信息化,时代化,节省人力物力,提高效率。基于这一点,开发此学生公寓管理软件…

探索计算机网络的奥秘:网络体系结构之深度解析

探索计算机网络的奥秘&#xff1a;网络体系结构之深度解析 本文以严谨的论述和详细的实例展开探讨计算机网络的核心概念与技术&#xff0c;带领读者深入理解网络体系结构的基本原理。 目录 引言网络体系结构的层次 物理层数据链路层网络层传输层应用层 TCP/IP 协议族OSI 参考模…

【SQL应知应会】分析函数的点点滴滴(二)

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 分析函数的点点滴滴 1.什么是分析函数&#xff1a;…

[进阶]Java:文件字节输出流、文件拷贝、资源释放

文件字节输出流&#xff08;FileOutputStream&#xff09;写数据出去的API 流的关闭和刷新 代码演示如下&#xff1a; ​​​​​​​ public class OutputStreamDemo04 {public static void main(String[] args) throws Exception {//1.创建一个文件字节输出流管道与目标文件…

Schneider Electric EcoStruxure Control Expert 15.3 Crack

Schneider Electric EcoStruxure Control Expert 15.3专为使用施耐德电气的Modicon PLC&#xff08;可编程逻辑控制器&#xff09;的控制和自动化工程师量身定制。它提供了一系列功能和工具&#xff0c;以方便自动化应用程序的开发、部署和维护。 施耐德电气EcoStruxure控制专家…

王者荣耀大数据运营总结

围绕王者荣耀大数据运营&#xff0c;依托对局日志和好友关系&#xff0c;开展了王者周报、赛季总结和周年庆活动等项目。这些案例中&#xff0c;遇到了哪些挑战&#xff1f;每一个指标是如何计算的呢&#xff1f;作者&#xff1a;曾志浩&#xff0c;腾讯微信游戏中心&#xff0…

王者荣耀进阶教学攻速/移速/减伤机制/视野/意识

目录 攻速阈值移速机制减伤机制防御与减伤的计算公式穿透值护甲最佳收益值真实伤害免伤 格挡机制控制效果详解1、减速2、缴械3、沉默4、嘲讽5、击飞6、眩晕7、压制 经济获取视野机制视野暴露机制1、防御塔视野范围2、英雄/兵线视野3、视野技能4、草丛视野 意识1、对线/单挑意识…

VB+ACCESS超市管理系统设计(源代码+系统)

超市管理系统是典型的信息管理系统(MIS),其开发主要包括后台数据库的建立和维护以及前端应用程序的开发两个方面。对于前者要求建立起数据一致性和完整性强、数据安全性好的库。而对于后者则要求应用程序功能完备,易使用等特点。经过分析,我们使用 MICROSOFT公司的 VISUAL BASI…