@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, 但是数据本身并没有被修改 创建表 创建表的本质其实就是在…...
Mochi语言解析:轻量级编程语言的设计原理与应用实践
1. 项目概述:一个为现代应用而生的轻量级编程语言最近在社区里看到不少朋友在讨论mochilang/mochi这个项目,作为一个对编程语言设计和运行时实现有浓厚兴趣的老码农,我立刻就被吸引住了。简单来说,Mochi 是一个新兴的、以轻量级和…...
基于CircuitPython与PyPortal的交互式冒险游戏开发实战
1. 项目概述与核心价值如果你对嵌入式开发感兴趣,但又觉得从点灯、读传感器开始有些枯燥,或者你是一位创客、教育者,想找一个能融合编程、故事创作和硬件交互的趣味项目,那么基于CircuitPython和PyPortal的交互式冒险游戏开发&…...
Tmux智能代理:用Emoji可视化终端状态,提升开发效率与情境感知
1. 项目概述:一个让终端会话“活”起来的智能代理 如果你和我一样,每天有超过8小时的时间“泡”在终端里,与tmux、vim和各种命令行工具打交道,那你一定理解那种感觉——屏幕上是冰冷的文本、闪烁的光标和单调的日志输出。长时间面…...
Cursor AI 规则引擎:自动化编码规范与项目约束实践指南
1. 项目概述:一个为 Cursor 编辑器量身定制的规则引擎如果你和我一样,深度依赖 Cursor 这款 AI 驱动的代码编辑器,那你一定经历过这样的时刻:面对 AI 生成的代码,既惊叹于它的效率,又时常为它不遵守团队规范…...
树莓派Pico舵机控制库picoclaw:从PWM原理到多舵机机器人应用
1. 项目概述:一个为树莓派Pico量身打造的舵机控制库如果你玩过树莓派Pico,并且尝试过用它来控制舵机,那你大概率会遇到一个头疼的问题:Pico的MicroPython固件本身并没有内置专门的舵机控制库。这意味着你需要自己动手,…...
英矽智能对标宁德时代,AI 制药规模化复制难题待解!
AI 制药巨头“朋友圈”扩大AI 制药巨头的“朋友圈”越来越大了。“港股 AI 制药一哥”英矽智能日前宣布与谷歌云达成战略合作,要把 Gemini 大模型塞进自家 Pharma.AI 平台。这意味着英矽智能已不再满足于做一家“卖算法的”公司,而是要把自己变成药物发现…...
ARMv8处理器特性寄存器详解与应用实践
1. ARMv8处理器特性寄存器概述在ARMv8架构中,处理器特性寄存器(Identification Registers)是系统控制寄存器的重要组成部分,它们以位字段编码方式详细描述了处理器的功能特性。这些寄存器对于系统软件开发、性能优化和安全设计具有…...
LLM Wiki带火的「知识预编译」,Graphify能直接落地企业知识库吗?
你是不是也跟着 LLM Wiki、Graphify 的热度,兴冲冲试过用「知识预编译」改造企业知识库?一落地却发现,要么权限兜不住敏感数据,要么溯源找不到具体条款,要么上万份文档跑起来成本直接炸锅 —— 网红项目的「个人最佳实…...
PPTTimer终极指南:Windows演示时间管理的免费开源解决方案
PPTTimer终极指南:Windows演示时间管理的免费开源解决方案 【免费下载链接】ppttimer 一个简易的 PPT 计时器 项目地址: https://gitcode.com/gh_mirrors/pp/ppttimer 在重要的演示、会议或培训中,时间控制往往成为成功的关键。你是否曾在演讲时频…...
如何提升SQL存储过程逻辑复用_封装通用存储过程函数
SQL Server无函数式存储过程,需用标量函数(单值计算)或表值函数(结果集)替代;标量函数禁用DML和非确定性函数,ITVF性能优于MSTVF;MySQL函数须声明DETERMINISTIC等属性;跨…...
