@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, 但是数据本身并没有被修改 创建表 创建表的本质其实就是在…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...