0

0

使用 CDI 限定符解决接口注入歧义问题

碧海醫心

碧海醫心

发布时间:2025-10-20 12:54:07

|

525人浏览过

|

来源于php中文网

原创

使用 cdi 限定符解决接口注入歧义问题

本文旨在解决在使用 CDI(Contexts and Dependency Injection)时,由于接口存在多个实现类而导致的注入歧义问题。通过引入 CDI 限定符,我们将学习如何明确指定需要注入的实现类,从而避免注入失败,并确保应用程序的正确运行。文章将提供详细的代码示例和步骤,帮助读者理解和应用 CDI 限定符,提升 CDI 开发技能。

在使用 CDI 进行依赖注入时,如果一个接口有多个实现类,CDI 容器将无法确定应该注入哪个实现类,从而导致注入歧义错误。 本文将介绍如何使用 CDI 限定符来解决这个问题,并提供详细的代码示例和步骤。

理解 CDI 注入歧义

在 CDI 中,Bean 是通过其类型和限定符来识别的。默认情况下,类型是从定义 Bean 的 Bean 类的传递类型闭包派生的(或者从定义 Bean 的生产者方法/字段的返回类型派生的)。

例如,如果有一个接口 Hello,它有两个实现类 HelloImpl1 和 HelloImpl2,那么 CDI 容器会识别出两个具有以下类型的 Bean:

  • {Hello, HelloImpl1}
  • {Hello, HelloImpl2}

如果没有使用任何限定符,当尝试使用 @Inject Hello hello 注入 Hello 接口时,CDI 容器会发现有两个符合条件的 Bean,因此无法确定应该注入哪个 Bean,从而导致注入歧义错误。

使用 CDI 限定符解决歧义

解决 CDI 注入歧义的正确方法是使用 CDI 限定符。限定符允许我们为 Bean 添加额外的标识信息,从而使 CDI 容器能够区分不同的 Bean。

1. 定义限定符

首先,需要定义一个自定义的限定符。限定符本身是一个注解,需要使用 @Qualifier、@Retention 和 @Target 元注解进行标记。

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import jakarta.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface MyQualifier {
}

在上面的代码中,@MyQualifier 是我们自定义的限定符。@Retention(RUNTIME) 表示该注解在运行时保留,@Target 指定该注解可以应用于哪些元素(例如,类型、字段、方法、参数)。

2. 使用限定符标记 Bean

Blogcast™
Blogcast™

BlogcastTM是一个文本转语音的工具,允许用户创建播客、视频、电子学习课程的音频和音频书籍,而无需录制。

下载

接下来,需要使用自定义的限定符来标记需要区分的 Bean。

import jakarta.enterprise.context.Dependent;
import jakarta.inject.Named;

@Dependent // this is just an example, use any scope you need or have been using
@MyQualifier // specify qualifier of this bean
@Named("HelloImpl1")
public class HelloImpl1 implements Hello {
    // some very cool code
    @Override
    public String sayHello() {
        return "Hello from HelloImpl1";
    }
}
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Named;

@Dependent // this is just an example, use any scope you need or have been using
@Named("HelloImpl2")
public class HelloImpl2 implements Hello {
    // some very cool code
    @Override
    public String sayHello() {
        return "Hello from HelloImpl2";
    }
}

在上面的代码中,HelloImpl1 类使用 @MyQualifier 注解进行标记,表示它具有 MyQualifier 限定符。

3. 在注入点使用限定符

最后,需要在注入点使用相同的限定符来指定需要注入的 Bean。

import jakarta.inject.Inject;

public class MyClass {
    // declare the injection point with qualifier(s)
    @Inject
    @MyQualifier
    Hello helloBean;

    public void doSomething() {
        System.out.println(helloBean.sayHello());
    }
}

在上面的代码中,helloBean 字段使用 @MyQualifier 注解进行标记,表示需要注入具有 MyQualifier 限定符的 Hello 接口的实现类。

完整示例

以下是一个完整的示例,演示如何使用 CDI 限定符解决接口注入歧义问题:

// Hello.java
public interface Hello {
    String sayHello();
}

// HelloImpl1.java
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Named;

@Dependent // this is just an example, use any scope you need or have been using
@MyQualifier // specify qualifier of this bean
@Named("HelloImpl1")
public class HelloImpl1 implements Hello {
    // some very cool code
    @Override
    public String sayHello() {
        return "Hello from HelloImpl1";
    }
}

// HelloImpl2.java
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Named;

@Dependent // this is just an example, use any scope you need or have been using
@Named("HelloImpl2")
public class HelloImpl2 implements Hello {
    // some very cool code
    @Override
    public String sayHello() {
        return "Hello from HelloImpl2";
    }
}

// MyQualifier.java
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import jakarta.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface MyQualifier {
}

// MyClass.java
import jakarta.inject.Inject;

public class MyClass {
    // declare the injection point with qualifier(s)
    @Inject
    @MyQualifier
    Hello helloBean;

    public void doSomething() {
        System.out.println(helloBean.sayHello());
    }

    public static void main(String[] args) {
        // This part depends on your CDI container (e.g., Weld, OpenWebBeans)
        // Here's a simplified example using a hypothetical CDI container:
        MyClass myClass = CDI.current().select(MyClass.class).get();
        myClass.doSomething();
    }
}

注意事项

  • 确保限定符的 @Retention 设置为 RUNTIME,以便在运行时可以使用限定符。
  • 确保在 Bean 的声明和注入点使用相同的限定符。
  • 可以使用多个限定符来进一步区分 Bean。

总结

通过使用 CDI 限定符,我们可以解决接口注入歧义问题,并明确指定需要注入的实现类。 这可以提高应用程序的可靠性和可维护性,并使 CDI 注入更加灵活和强大。 建议阅读 CDI 规范,了解更多关于类型安全解析和限定符的信息。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

989

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

50

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

201

2025.12.29

go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

130

2025.07.29

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

3

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

1

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

5

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

6

2025.12.31

出现404解决方法大全
出现404解决方法大全

本专题整合了404错误解决方法大全,阅读专题下面的文章了解更多详细内容。

30

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.1万人学习

C# 教程
C# 教程

共94课时 | 5.7万人学习

Java 教程
Java 教程

共578课时 | 39.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号