首页 > 解决方案 > 当我已经使用 @Produces 注释时,为什么会出现“接口的模糊依赖项”异常?

问题描述

我在我的项目中使用了两个面向消息的中间件。RabbitMQ 和 Apache Kafka。我有一个由 ConsumerRabbitMQ 和 ConsumerKafka 实现的消费者接口 IConsume。在启动时经历一些条件,我使用@Produces 注释为我将注入的接口 Bean 选择一个实现,但它给了我这个错误。

例外一:

org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type IConsume with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private com.mycompany.chatapp.startup.RunConsumers.ct
  at com.mycompany.chatapp.startup.RunConsumers.ct(RunConsumers.java:0)
  Possible dependencies: 
  - Session bean [class com.mycompany.chatapp.messagegateway.ConsumerRabbitMQ with qualifiers [@Any @Default]; local interfaces are [IConsume],
  - Producer Method [IConsume] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces public com.mycompany.chatapp.startup.MOMConfigBean.produceIConsume()],
  - Session bean [class com.mycompany.chatapp.messagegateway.ConsumerKafka with qualifiers [@Any @Default]; local interfaces are [IConsume]

@Default 和 @Alternative 有效,但我希望它通过检查哪个中间件正在运行来进行选择。

查找有效,我也尝试了 beanName。我认为问题出在@Produces,但我找不到看起来是什么。

import javax.enterprise.inject.Produces;

@Singleton
@Startup
public class MOMConfigBean {
private String mom;


@PostConstruct
public void init() {
    mom = "Kafka";
}

@EJB(lookup = "java:global/Chatapp/ConsumerKafka!com.mycompany.chatapp.messagegateway.IConsume")
IConsume kafkaConsumer;

@EJB(lookup = "java:global/Chatapp/ConsumerRabbitMQ!com.mycompany.chatapp.messagegateway.IConsume")
IConsume rabbitConsumer;

@Produces
public IConsume produceIConsume() {
    if ("Kafka".equals(mom)) {
        return kafkaConsumer;
    } else {
        return rabbitConsumer;
    }
}


public interface IConsume {
// some code
}

@Stateless
public class ConsumerKafka implements IConsume{
// some code
}

@Stateless
public class ConsumerRabbitMQ implements IConsume {
// some code
}

public class runConsumers{

@Inject
private IConsume ct;

}

标签: ejbjava-ee-7

解决方案


您有三个不明确的IConsume实例来源:

  1. 一个ConsumerKafkaEJB
  2. 一个ConsumerRabbitMQEJB
  3. 一种@Produces public IConsume produceIConsume()方法。

您需要IConsume使用限定符来消除实例来源的歧义。

这个限定符看起来像:

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

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD})
public @interface ConditionalMom {
}

然后限定生产者:

@Produces
@ConditionalMom
public IConsume produceIConsume() {
    if ("Kafka".equals(mom)) {
        return kafkaConsumer;
    } else {
        return rabbitConsumer;
    }
}

和注射部位:

public class runConsumers{

    @Inject
    @ConditionalMom
    private IConsume ct;

}

现在您有了一个单一的@ConditionalMom IConsume实例来源,因此它不再模棱两可。

当您开始进一步利用 CDI 功能时,您会发现您将到处使用限定符。


推荐阅读