@Inject @Qualifier @Named
@Inject @Qualifier @Named
在依赖注入(DI)中,@Inject
、@Qualifier
和 @Named
是用于管理对象创建和绑定的关键注解。以下是它们的用途、依赖配置和代码示例的详细说明:
1. 注解的作用
@Inject
:标记需要注入的构造函数、字段或方法(JSR-330 标准)。@Qualifier
:定义自定义注解,用于解决同一类型多个实现的依赖冲突。@Named
:基于字符串名称的限定符(@Qualifier
的简化版),直接用于区分实现。
2. 依赖配置
Maven (pom.xml
) - 使用 javax.inject
(传统 Java EE)
<dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version>
</dependency>
Maven (pom.xml
) - 使用 Jakarta EE
<dependency><groupId>jakarta.inject</groupId><artifactId>jakarta.inject-api</artifactId><version>2.0.1</version>
</dependency>
Gradle (build.gradle.kts
) - Kotlin DSL
dependencies {// Java EEimplementation("javax.inject:javax.inject:1")// 或 Jakarta EEimplementation("jakarta.inject:jakarta.inject-api:2.0.1")
}
3. 代码示例
场景:多个 Service
实现,需通过名称或限定符区分
步骤 1:定义接口和实现类
public interface Service {void execute();
}// 实现类 1
public class EmailService implements Service {@Overridepublic void execute() {System.out.println("Sending email...");}
}// 实现类 2
public class SmsService implements Service {@Overridepublic void execute() {System.out.println("Sending SMS...");}
}
步骤 2:使用 @Named
注解区分实现
import javax.inject.Inject;
import javax.inject.Named;public class Client {private final Service service;// 通过名称注入特定实现@Injectpublic Client(@Named("email") Service service) {this.service = service;}public void run() {service.execute();}
}
步骤 3:配置依赖注入框架(以 Dagger 2 为例)
-
添加 Dagger 依赖:
<!-- Maven --> <dependency><groupId>com.google.dagger</groupId><artifactId>dagger</artifactId><version>2.50</version> </dependency> <dependency><groupId>com.google.dagger</groupId><artifactId>dagger-compiler</artifactId><version>2.50</version><scope>provided</scope> </dependency>
// Gradle dependencies {implementation("com.google.dagger:dagger:2.50")kapt("com.google.dagger:dagger-compiler:2.50") }
-
定义模块和绑定:
import dagger.Module; import dagger.Provides; import javax.inject.Named;@Module public class AppModule {@Provides@Named("email")Service provideEmailService() {return new EmailService();}@Provides@Named("sms")Service provideSmsService() {return new SmsService();} }
-
创建组件并注入:
import dagger.Component;@Component(modules = AppModule.class) public interface AppComponent {Client getClient(); }// 使用 public class Main {public static void main(String[] args) {AppComponent component = DaggerAppComponent.create();Client client = component.getClient();client.run(); // 输出: Sending email...} }
步骤 4:自定义 @Qualifier
(替代 @Named
)
-
定义自定义限定符注解:
import javax.inject.Qualifier; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface Email {}@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface Sms {}
-
在模块中使用自定义限定符:
@Module public class AppModule {@Provides@EmailService provideEmailService() {return new EmailService();}@Provides@SmsService provideSmsService() {return new SmsService();} }
-
在客户端注入:
public class Client {private final Service service;@Injectpublic Client(@Email Service service) {this.service = service;} }
4. 常见问题解决
错误:No qualifying bean of type 'Service'
- 原因:未明确指定使用哪个实现。
- 修复:添加
@Named
或自定义@Qualifier
注解。
依赖未生效
- 检查:确保依赖注入框架(如 Dagger、Guice、Spring)已正确配置,并生成必要的代码(如 Dagger 需运行
kapt
或annotationProcessor
)。
迁移到 Jakarta EE
- 操作:将
javax.inject
替换为jakarta.inject
,并更新所有导入语句。
5. 总结
@Inject
:标记注入点。@Named
:通过字符串名称区分实现。@Qualifier
:定义更类型安全的限定符。- 框架适配:根据使用的 DI 工具(Dagger、Spring、Guice)调整配置。
通过合理使用这些注解,可以优雅地管理复杂的依赖关系。
在依赖注入(DI)框架中,如 Spring 或 Google Guice,@Inject
、@Qualifier
和 @Named
是用于控制依赖注入行为的注解。
-
@Inject
:@Inject
注解用于标记一个字段、方法或构造函数,表明应该通过依赖注入框架来注入其依赖项。- 在 Spring 中,
@Inject
是 JSR-330 标准的一部分,它是@Autowired
的一个替代方案,但两者在功能上是等效的。 - 使用
@Inject
可以让代码更加标准化,因为它不依赖于 Spring 特定的注解。
-
@Qualifier
:@Qualifier
注解用于在存在多个相同类型的 bean 时,帮助 DI 框架区分应该注入哪个具体的 bean。- 它通常与自定义注解一起使用,这些自定义注解被标记为
@Qualifier
的元注解。 - 在 Spring 中,如果你有两个相同类型的 bean,并且你想通过名称或其他标准来区分它们,你可以使用
@Qualifier
注解。
-
@Named
:@Named
注解是 JSR-330 标准的一部分,它提供了一种简单的方法来指定应该注入哪个 bean,当存在多个相同类型的 bean 时。- 在 Spring 中,
@Named
可以作为@Qualifier
的一个替代方案,用于通过名称来区分 bean。 - 与
@Qualifier
不同,@Named
本身就是一个注解,而不需要与自定义注解一起使用。
示例
假设你有一个接口 MyService
和两个实现 MyServiceImpl1
和 MyServiceImpl2
。
public interface MyService {void doSomething();
}@Service("service1")
public class MyServiceImpl1 implements MyService {@Overridepublic void doSomething() {System.out.println("Doing something in MyServiceImpl1");}
}@Service("service2")
public class MyServiceImpl2 implements MyService {@Overridepublic void doSomething() {System.out.println("Doing something in MyServiceImpl2");}
}
在另一个类中,如果你想注入 MyServiceImpl1
,你可以这样做:
public class MyClient {// 使用 @Inject 和 @Named 来指定要注入的 bean@Inject@Named("service1")private MyService myService;public void performAction() {myService.doSomething();}
}
或者,如果你更喜欢使用 @Qualifier
,你可以定义一个自定义注解,并使用它来指定要注入的 bean:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
public @interface Service1Qualifier {
}// 在 MyServiceImpl1 上添加 @Service1Qualifier(这通常不是必需的,除非你有特定的逻辑需要这样做)
// 但在注入点使用它:public class MyClient {// 使用 @Inject 和 @Service1Qualifier 来指定要注入的 bean@Inject@Service1Qualifierprivate MyService myService;public void performAction() {myService.doSomething();}
}// 你还需要在配置中指定哪个 bean 应该与 @Service1Qualifier 关联,这通常是通过 Java 配置或 XML 配置来完成的。
请注意,在上面的 @Service1Qualifier
示例中,我通常不会在 MyServiceImpl1
上使用 @Service1Qualifier
注解,而是直接在注入点使用它,并通过配置来指定哪个 bean 应该被注入。然而,如果你有一个特定的用例需要在实现类上使用它,那也是可以的。
在 Spring Boot 中,你通常不需要显式地定义 @Qualifier
的自定义实现,因为 @Named
已经提供了足够的功能来通过名称区分 bean。但是,如果你想要更复杂的逻辑或更清晰的代码结构,定义自定义的 @Qualifier
注解可能是有意义的。
在使用依赖注入(Dependency Injection, DI)时,@Inject
、@Qualifier
和 @Named
注解用于指定和限定依赖项。它们是 Java 依赖注入规范(JSR-330)和相关框架的一部分。下面是对这些注解的简要介绍以及如何在项目中引入相应的依赖。
@Inject
@Inject
是 JSR-330 标准的一部分,用来标记一个构造器、方法或字段应该通过依赖注入来提供依赖。
@Qualifier
@Qualifier
是一个元注解(即它被用来创建其他注解),用于限定依赖类型,当有多个相同类型的依赖需要注入时,可以使用自定义的限定符注解来区分不同的实现。
@Named
@Named
是 @Qualifier
的一个具体实现,允许你通过名称来限定依赖。它是 Jakarta 或 javax 注入包中的一个标准注解。
Maven/Gradle 引入依赖
对于 Gradle Kotlin DSL (build.gradle.kts
) 或 Groovy 版本 (build.gradle
) 的构建脚本,根据你需要的版本选择合适的依赖:
- Jakarta EE (2.0.1 或更新版本)
// build.gradle.kts
dependencies {implementation("jakarta.inject:jakarta.inject-api:2.0.1") // 确保选择适合你的最新版本
}
或者 Groovy 版本:
// build.gradle
dependencies {implementation 'jakarta.inject:jakarta.inject-api:2.0.1' // 确保选择适合你的最新版本
}
- javax (适用于旧版本)
如果你必须使用旧版本的 javax
注解,可以这样添加依赖:
// build.gradle.kts
dependencies {implementation("javax.inject:javax.inject:1")
}
或者 Groovy 版本:
// build.gradle
dependencies {implementation 'javax.inject:javax.inject:1'
}
注意:由于包名从 javax.*
更改为 jakarta.*
,如果你是在2025年进行开发,并且没有特别的需求去支持旧版本,推荐使用 jakarta.inject
相关的依赖。
此外,若你在使用特定框架如 Spring,它也提供了自己的 @Qualifier
和 @Named
实现,可以直接使用而不需要额外添加上述依赖。确保查阅所使用框架的官方文档以获取更详细的指导。
相关文章:

@Inject @Qualifier @Named
Inject Qualifier Named 在依赖注入(DI)中,Inject、Qualifier 和 Named 是用于管理对象创建和绑定的关键注解。以下是它们的用途、依赖配置和代码示例的详细说明: 1. 注解的作用 Inject:标记需要注入的构造函数、字段…...

创建 priority_queue - 进阶(内置类型)c++
内置类型就是 C 提供的数据类型,⽐如 int 、 double 、 long long 等。以 int 类型为例,分 别创建⼤根堆和⼩根堆。 这种写法意思是,我要告诉这个优先级队列要建一个什么样的堆,第一个int是要存什么数据类型,vecto…...

2. Java-MarkDown文件解析-工具类
2. Java-MarkDown文件解析-工具类 1. 思路 读取markdown文件的内容,根据markdown的语法进行各个类型语法的解析。引入工具类 commonmark 和 commonmark-ext-gfm-tables进行markdown语法解析。 2. 工具类 pom.xml <!-- commonmark 解析markdown --> <d…...

动态规划DP 最长上升子序列模型 登山(题目分析+C++完整代码)
概览检索 动态规划DP 最长上升子序列模型 登山 原题链接 AcWing 1014. 登山 题目描述 五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个…...

css-设置元素的溢出行为为可见overflow: visible;
1.前言 overflow 属性用于设置当元素的内容溢出其框时如何处理。 2. overflow overflow 属性的一些常见值: 1 visible:默认值。内容不会被剪裁,会溢出元素的框。 2 hidden:内容会被剪裁,不会显示溢出的部分。 3 sc…...

家居EDI:Hom Furniture EDI需求分析
HOM Furniture 是一家成立于1977年的美国家具零售商,总部位于明尼苏达州。公司致力于提供高品质、时尚的家具和家居用品,满足各种家庭和办公需求。HOM Furniture 以广泛的产品线和优质的客户服务在市场上赢得了良好的口碑。公司经营的产品包括卧室、客厅…...

1、开始简单使用rag
文章目录 前言数据存放申请api开始代码安装依赖从文件夹中读取文档文档切块将分割嵌入并存储在向量库中检索部分代码构造用户接口演示提示 整体代码 前言 本章只是简单使用rag的一个示例,为了引出以后的学习,将整个rag的流程串起来 数据存放 一个示例…...

Linux Samba 低版本漏洞(远程控制)复现与剖析
目录 前言 漏洞介绍 漏洞原理 产生条件 漏洞影响 防御措施 复现过程 结语 前言 在网络安全的复杂生态中,系统漏洞的探索与防范始终是保障数字世界安全稳定运行的关键所在。Linux Samba 作为一款在网络共享服务领域应用极为广泛的软件,其低版本中…...

安卓(android)实现注册界面【Android移动开发基础案例教程(第2版)黑马程序员】
一、实验目的(如果代码有错漏,可查看源码) 1.掌握LinearLayout、RelativeLayout、FrameLayout等布局的综合使用。 2.掌握ImageView、TextView、EditText、CheckBox、Button、RadioGroup、RadioButton、ListView、RecyclerView等控件在项目中的…...

【 AI agents】letta:2024年代理堆栈演进(中英文翻译)
The AI agents stack AI 代理堆栈 November 14, 2024 11月 14, 2024原文: The AI agents stack官方教程教程学习笔记: 【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理Understanding the AI agents landscape 了解 AI 代理环境 Although we see a …...

Java中 instanceof 的用法(详解)
目录 引言 基本语法 基本作用 1. 检查对象是否是指定类的实例 2. 检查对象是否是子类的实例 3. 检查对象是否实现某个接口 4.null 处理 错误分析: 5.综合对比示例 最后总结 注意事项 引言 instanceof 概念在多态中引出,因为在多态发生时&…...

联想拯救者R720笔记本外接显示屏方法,显示屏是2K屏27英寸
晚上23点10分前下单,第二天上午显示屏送到,检查外包装没拆封过。这个屏幕左下方有几个按键,按一按就开屏幕、按一按就关闭屏幕,按一按方便节省时间,也支持阅读等模式。 显示屏是 :AOC 27英寸 2K高清 100Hz…...

【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础
文章目录 1. 前言 本文章基于 RocketMQ 4.9.3 1. 前言 RocketMQ 存储部分系列文章: 【RocketMQ 存储】- RocketMQ存储类 MappedFile 【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础 【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础...

S4 HANA明确税金本币和外币之间转换汇率确定(OBC8)
本文主要介绍在S4 HANA OP中明确明确税金本币和外币之间转换汇率确定(OBC8)相关设置。具体请参照如下内容: 明确税金本币和外币之间转换汇率确定(OBC8) 以上配置,我们可以根据不同公司代码所配置的使用不同的汇率来对税金外币和本币之间进行换算。来针对…...

Cocos Creator 3.8 2D 游戏开发知识点整理
目录 Cocos Creator 3.8 2D 游戏开发知识点整理 1. Cocos Creator 3.8 概述 2. 2D 游戏核心组件 (1) 节点(Node)与组件(Component) (2) 渲染组件 (3) UI 组件 3. 动画系统 (1) 传统帧动画 (2) 动画编辑器 (3) Spine 和 …...

梯度提升用于高效的分类与回归
使用 决策树(Decision Tree) 实现 梯度提升(Gradient Boosting) 主要是模拟 GBDT(Gradient Boosting Decision Trees) 的原理,即: 第一棵树拟合原始数据计算残差(负梯度…...

【单细胞第二节:单细胞示例数据分析-GSE218208】
GSE218208 1.创建Seurat对象 #untar(“GSE218208_RAW.tar”) rm(list ls()) a data.table::fread("GSM6736629_10x-PBMC-1_ds0.1974_CountMatrix.tsv.gz",data.table F) a[1:4,1:4] library(tidyverse) a$alias:gene str_split(a$alias:gene,":",si…...

设计模式 - 行为模式_Template Method Pattern模板方法模式在数据处理中的应用
文章目录 概述1. 核心思想2. 结构3. 示例代码4. 优点5. 缺点6. 适用场景7. 案例:模板方法模式在数据处理中的应用案例背景UML搭建抽象基类 - 数据处理的 “总指挥”子类定制 - 适配不同供应商供应商 A 的数据处理器供应商 B 的数据处理器 在业务代码中整合运用 8. 总…...

新春登蛇山:告别岁月,启航未来
大年初一,晨曦透过薄雾,温柔地洒在武汉的大街小巷。2025 年的蛇年春节,带着新春的喜气与希望悄然而至。我站在蛇山脚下,心中涌动着复杂的情感,因为今天,我不仅将与家人一起登山揽胜,更将在这一天…...

hive:基本数据类型,关于表和列语法
基本数据类型 Hive 的数据类型分为基本数据类型和复杂数据类型 加粗的是常用数据类型 BOOLEAN出现ture和false外的其他值会变成NULL值 没有number,decimal类似number 如果输入的数据不符合数据类型, 映射时会变成NULL, 但是数据本身并没有被修改 创建表 创建表的本质其实就是在…...

安装最小化的CentOS7后,执行yum命令报错Could not resolve host mirrorlist.centos.org; 未知的错误
文章目录 安装最小化的CentOS7后,执行yum命令报错"Could not resolve host: mirrorlist.centos.org; 未知的错误"错误解决方案: 安装最小化的CentOS7后,执行yum命令报错"Could not resolve host: mirrorlist.centos.org; 未知…...

图论——spfa判负环
负环 图 G G G中存在一个回路,该回路边权之和为负数,称之为负环。 spfa求负环 方法1:统计每个点入队次数, 如果某个点入队n次, 说明存在负环。 证明:一个点入队n次,即被更新了n次。一个点每次被更新时所对应最短路的边数一定是…...

软件工程概论试题三
一、单选 1.需求确认主要检査五个方面的内容,其中那一项是为了保证文档中的需求不互相冲突(即不应该有相互矛盾的约束或者对同一个系统功能有不同的描述)。 A.现实性 B. 可验证性 C.一致性 D.正确性 E.完整性 正答:C 2.下列开发方法中,( )不…...

21.3-启动流程、编码风格(了解) 第21章-FreeRTOS项目实战--基础知识之新建任务、启动流程、编码风格、系统配置 文件组成和编码风格(了解)
21.3-启动流程、编码风格(了解) 启动流程 第一种启动流程(我们就使用这个): 在main函数中将硬件初始化、RTOS系统初始化,同时创建所有任务,再启动RTOS调度器。 第二种启动流程: 在main函数中将硬件初始化、RTOS系统初始化,只…...

未来无线技术的发展方向
未来无线技术的发展趋势呈现出多样化、融合化的特点,涵盖速度、覆盖范围、应用领域、频段利用、安全性等多个方面。这些趋势将深刻改变人们的生活和社会的运行方式。 传输速度提升:Wi-Fi 技术迭代加快,如 Wi-Fi7 理论峰值速率达 46Gbps&#…...

Qt5离线安装包无法下载问题解决办法
想在电脑里装一个Qt,但是直接报错。果然还是有解决办法滴。 qt download from your ip is not allowed Qt5安装包下载办法 方法一:简单直接,直接科学一下,不过违法行为咱不做,遵纪守法好公民(不过没办法阻…...

qt-C++笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphicsRectItem的区别
qt-C笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphicsRectItem的区别 code review! 参考笔记 1.qt-C笔记之重写QGraphicsItem的paint方法(自定义QGraphicsItem) 文章目录 qt-C笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphic…...

doris:导入时实现数据转换
Doris 在数据导入时提供了强大的数据转换能力,可以简化部分数据处理流程,减少对额外 ETL 工具的依赖。主要支持以下四种转换方式: 列映射:将源数据列映射到目标表的不同列。 列变换:使用函数和表达式对源数据进行实时…...

新版231普通阿里滑块 自动化和逆向实现 分析
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向过程 补环境逆向 部分补环境 …...

如何构建树状的思维棱镜认知框架
在思维与知识管理中,“树状思维棱镜”通常指一种层级式、可多维度展开和不断深入(下钻)的认知框架。它不仅仅是普通的树状结构(如传统思维导图),更强调“棱镜”所体现的多视角、多维度切换与综合分析的能力…...