@Inject @Qualifier @Named

news2025/2/1 4:11:57

@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 EE
    implementation("javax.inject:javax.inject:1")
    // 或 Jakarta EE
    implementation("jakarta.inject:jakarta.inject-api:2.0.1")
}

3. 代码示例

场景:多个 Service 实现,需通过名称或限定符区分
步骤 1:定义接口和实现类
public interface Service {
    void execute();
}

// 实现类 1
public class EmailService implements Service {
    @Override
    public void execute() {
        System.out.println("Sending email...");
    }
}

// 实现类 2
public class SmsService implements Service {
    @Override
    public void execute() {
        System.out.println("Sending SMS...");
    }
}
步骤 2:使用 @Named 注解区分实现
import javax.inject.Inject;
import javax.inject.Named;

public class Client {
    private final Service service;

    // 通过名称注入特定实现
    @Inject
    public Client(@Named("email") Service service) {
        this.service = service;
    }

    public void run() {
        service.execute();
    }
}
步骤 3:配置依赖注入框架(以 Dagger 2 为例)
  1. 添加 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")
    }
    
  2. 定义模块和绑定

    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();
        }
    }
    
  3. 创建组件并注入

    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
  1. 定义自定义限定符注解

    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 {}
    
  2. 在模块中使用自定义限定符

    @Module
    public class AppModule {
        @Provides
        @Email
        Service provideEmailService() {
            return new EmailService();
        }
    
        @Provides
        @Sms
        Service provideSmsService() {
            return new SmsService();
        }
    }
    
  3. 在客户端注入

    public class Client {
        private final Service service;
    
        @Inject
        public Client(@Email Service service) {
            this.service = service;
        }
    }
    

4. 常见问题解决

错误:No qualifying bean of type 'Service'
  • 原因:未明确指定使用哪个实现。
  • 修复:添加 @Named 或自定义 @Qualifier 注解。
依赖未生效
  • 检查:确保依赖注入框架(如 Dagger、Guice、Spring)已正确配置,并生成必要的代码(如 Dagger 需运行 kaptannotationProcessor)。
迁移到 Jakarta EE
  • 操作:将 javax.inject 替换为 jakarta.inject,并更新所有导入语句。

5. 总结

  • @Inject:标记注入点。
  • @Named:通过字符串名称区分实现。
  • @Qualifier:定义更类型安全的限定符。
  • 框架适配:根据使用的 DI 工具(Dagger、Spring、Guice)调整配置。

通过合理使用这些注解,可以优雅地管理复杂的依赖关系。




在依赖注入(DI)框架中,如 Spring 或 Google Guice,@Inject@Qualifier@Named 是用于控制依赖注入行为的注解。

  1. @Inject

    • @Inject 注解用于标记一个字段、方法或构造函数,表明应该通过依赖注入框架来注入其依赖项。
    • 在 Spring 中,@Inject 是 JSR-330 标准的一部分,它是 @Autowired 的一个替代方案,但两者在功能上是等效的。
    • 使用 @Inject 可以让代码更加标准化,因为它不依赖于 Spring 特定的注解。
  2. @Qualifier

    • @Qualifier 注解用于在存在多个相同类型的 bean 时,帮助 DI 框架区分应该注入哪个具体的 bean。
    • 它通常与自定义注解一起使用,这些自定义注解被标记为 @Qualifier 的元注解。
    • 在 Spring 中,如果你有两个相同类型的 bean,并且你想通过名称或其他标准来区分它们,你可以使用 @Qualifier 注解。
  3. @Named

    • @Named 注解是 JSR-330 标准的一部分,它提供了一种简单的方法来指定应该注入哪个 bean,当存在多个相同类型的 bean 时。
    • 在 Spring 中,@Named 可以作为 @Qualifier 的一个替代方案,用于通过名称来区分 bean。
    • @Qualifier 不同,@Named 本身就是一个注解,而不需要与自定义注解一起使用。

示例

假设你有一个接口 MyService 和两个实现 MyServiceImpl1MyServiceImpl2

public interface MyService {
    void doSomething();
}

@Service("service1")
public class MyServiceImpl1 implements MyService {
    @Override
    public void doSomething() {
        System.out.println("Doing something in MyServiceImpl1");
    }
}

@Service("service2")
public class MyServiceImpl2 implements MyService {
    @Override
    public 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
    @Service1Qualifier
    private 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 实现,可以直接使用而不需要额外添加上述依赖。确保查阅所使用框架的官方文档以获取更详细的指导。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2289152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【已解决】windows7虚拟机安装VMtools频繁报错

为了在虚拟机VMware中安装win7&#xff0c;题主先在网上下载了windows7 professional版本的镜像&#xff0c;在vmware中安装vmtools时报错&#xff0c;信息如下 &#xff08;安装程序无法继续&#xff0c;本程序需要您将此虚拟机上安装的操作系统更新到SP1&#xff09; 然后就…

【PyTorch】6.张量运算函数:一键开启!PyTorch 张量函数的宝藏工厂

目录 1. 常见运算函数 个人主页&#xff1a;Icomi 专栏地址&#xff1a;PyTorch入门 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&#xff0c;为构建和训练神经网络提供了高效且灵活的平台。神经网络作为人工智能的核心技术&…

【浏览器 - Mac实时调试iOS手机浏览器页面】

最近开发个项目&#xff0c;需要在 Mac 电脑上调试 iOS 手机设备上的 Chrome 浏览器&#xff0c;并查看Chrome网页上的 console 信息&#xff0c;本来以为要安装一些插件&#xff0c;没想到直接使用Mac上的Safari 直接可以调试&#xff0c;再此记录下&#xff0c;分享给需要的伙…

PyQt5之QtDesigner的若干配置和使用

1.描述 QtDesigner是一个可视化工具&#xff0c;可以通过该工具设计页面 2.简单使用 1.下载PyQt5-tools pip install pyqt5-tools 2.打开designer.exe文件 我采用的是虚拟环境&#xff0c;该文件位于C:\Users\24715\anaconda3\envs\pyqt\Lib\site-packages\qt5_applicatio…

侯捷C++day01

一个类该准备什么样的数据、函数。才能满足使用这个类人的需求。 inline关键字是建议编译器做inline处理。 private只有本类可以看到。 C创建对象会自动调用构造函数。不可能在程序中显示调用构造函数。不带指针的类多半不用写析构函数。 以下两个重载构造函数会发生错误 不允许…

CTF-web: phar反序列化+数据库伪造 [DASCTF2024最后一战 strange_php]

step 1 如何触发反序列化? 漏洞入口在 welcome.php case delete: // 获取删除留言的路径&#xff0c;优先使用 POST 请求中的路径&#xff0c;否则使用会话中的路径 $message $_POST[message_path] ? $_POST[message_path] : $_SESSION[message_path]; $msg $userMes…

Win11下帝国时代2无法启动解决方法

鼠标右键点图标&#xff0c;选择属性 点开始&#xff0c;输入启用和关闭

GSI快速收录服务:让你的网站内容“上架”谷歌

辛苦制作的内容无法被谷歌抓取和展示&#xff0c;导致访客无法找到你的网站&#xff0c;这是会让人丧失信心的事情。GSI快速收录服务就是为了解决这种问题而存在的。无论是新上线的页面&#xff0c;还是长期未被收录的内容&#xff0c;通过我们的技术支持&#xff0c;都能迅速被…

mysql_init和mysql_real_connect的形象化认识

解析总结 1. mysql_init 的作用 mysql_init 用于初始化一个 MYSQL 结构体&#xff0c;为后续数据库连接和操作做准备。该结构体存储连接配置及状态信息&#xff0c;是 MySQL C API 的核心句柄。 示例&#xff1a; MYSQL *conn mysql_init(NULL); // 初始化连接句柄2. mysql_…

python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。 按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位异或运算&#xff1a; 两个等长度二进制数上下对齐&#xff0c;相…

基础项目实战——学生管理系统(c++)

目录 前言一、功能菜单界面二、类与结构体的实现三、录入学生信息四、删除学生信息五、更改学生信息六、查找学生信息七、统计学生人数八、保存学生信息九、读取学生信息十、打印所有学生信息十一、退出系统十二、文件拆分结语 前言 这一期我们来一起学习我们在大学做过的课程…

春节期间,景区和酒店如何合理用工?

春节期间&#xff0c;景区和酒店如何合理用工&#xff1f; 春节期间&#xff0c;旅游市场将迎来高峰期。景区与酒店&#xff0c;作为旅游产业链中的两大核心环节&#xff0c;承载着无数游客的欢乐与期待。然而&#xff0c;也隐藏着用工管理的巨大挑战。如何合理安排人力资源&a…

Linux Samba 低版本漏洞(远程控制)复现与剖析

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

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.27 线性代数王国:矩阵分解实战指南

1.27 线性代数王国&#xff1a;矩阵分解实战指南 #mermaid-svg-JWrp2JAP9qkdS2A7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JWrp2JAP9qkdS2A7 .error-icon{fill:#552222;}#mermaid-svg-JWrp2JAP9qkdS2A7 .erro…

初二回娘家

昨天下午在相亲相爱一家人群里聊天&#xff0c;今天来娘家拜年。 聊天结束后&#xff0c;开始准备今天的菜肴&#xff0c;梳理了一下&#xff0c;凉菜&#xff0c;热菜&#xff0c;碗菜。 上次做菜&#xff0c;粉丝感觉泡的不透&#xff0c;有的硬&#xff0c;这次使用开水浸泡…

【Block总结】PKI 模块,无膨胀多尺度卷积,增强特征提取的能力|即插即用

论文信息 标题: Poly Kernel Inception Network for Remote Sensing Detection 作者: Xinhao Cai, Qiuxia Lai, Yuwei Wang, Wenguan Wang, Zeren Sun, Yazhou Yao 论文链接&#xff1a;https://arxiv.org/pdf/2403.06258 代码链接&#xff1a;https://github.com/NUST-Mac…

Blazor-@bind

数据绑定 带有 value属性的标记都可以使用bind 绑定&#xff0c;<div>、<span>等非输入标记&#xff0c;无法使用bind 指令的&#xff0c;默认绑定了 onchange 事件&#xff0c;onchange 事件是指在输入框中输入内容之后&#xff0c;当失去焦点时执行。 page &qu…

架构技能(六):软件设计(下)

我们知道&#xff0c;软件设计包括软件的整体架构设计和模块的详细设计。 在上一篇文章&#xff08;见 《架构技能&#xff08;五&#xff09;&#xff1a;软件设计&#xff08;上&#xff09;》&#xff09;谈了软件的整体架构设计&#xff0c;今天聊一下模块的详细设计。 模…

C++并发编程指南07

文章目录 [TOC]5.1 内存模型5.1.1 对象和内存位置图5.1 分解一个 struct&#xff0c;展示不同对象的内存位置 5.1.2 对象、内存位置和并发5.1.3 修改顺序示例代码 5.2 原子操作和原子类型5.2.1 标准原子类型标准库中的原子类型特殊的原子类型备选名称内存顺序参数 5.2.2 std::a…

MySQL 容器已经停止(但仍然存在),但希望重新启动它,并使它的 3306 端口映射到宿主机的 3306 端口是不可行的

重新启动容器并映射端口是不行的 由于你已经有一个名为 mysql-container 的 MySQL 容器&#xff0c;你可以使用 docker start 启动它。想要让3306 端口映射到宿主机是不行的&#xff0c;实际上&#xff0c;端口映射是在容器启动时指定的。你无法在容器已经创建的情况下直接修改…