EJB的CDI生产者

时间:2016-02-18 13:38:26

标签: java-ee jboss ejb cdi wildfly

我尝试使用POJO作为CDI生产者来注入正确的EJB,但我得到 org.jboss.weld.exceptions.UnsatisfiedResolutionException:WELD-001308

这是我的制片人POJO

public class STGatewayUtilProducer {

    @Produces
    @Chosen
    public ISTGatewayUtil getISTGatewayUtil(Instance<STGatewayWSUtil> ws, Instance<STGatewayMQTTUtil> mqtt, ConfigurationManager cm) {
        switch(cm.getGatewayProtocol()) {
            case ConfigurationManager.GATEWAY_PROTOCOL_TYPE_MQTT:
                return mqtt.get();
            default:
                return ws.get();
        }
    }

}

这是限定符定义:

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

这些是EJB声明:

@Stateless
public class STGatewayMQTTUtil implements Serializable, ISTGatewayUtil {
    ...
}

@Stateless
public class STGatewayWSUtil implements Serializable, ISTGatewayUtil {
    ...
}

最后,这就是我注入EJB的方式:

@Inject
@Chosen
private Instance<ISTGatewayUtil> gtwUtil;

我正面临JBoss AS 7和WildFly 10的问题。

修改

我找到了问题的核心!我声明了一个公共abstract父类,它实现了ejb接口,让我的会话bean扩展它:使用这种结构,bean无法解析。

相反,如果我在会话bean上移动implements子句,问题就会消失:有人可能会解释我的类层次结构有什么问题吗?

2 个答案:

答案 0 :(得分:2)

引用specification

  

3.2.2。会话bean的Bean类型

     

会话bean的无限制bean类型包含all   bean的本地接口及其超接口。如果是会话   bean有一个无界面视图,一组不受限制的bean类型   包含bean类和所有超类。此外,   java.lang.Object是每个会话bean的bean类型。

     

远程接口不包含在bean类型集中。

所以这里因为你的会话bean都有一个本地接口,所以它们的bean类型集合中没有它们的类。因此,你无法用他们的班级解决这些问题是正常的。

您需要向会话bean定义添加额外信息,以便能够区分它们或将它们声明为带有@LocalBean注释的No-Interface视图EJB。 这是您的代码的新版本,将您的EJB声明为NIV

@Stateless
@LocalBean 
public class STGatewayMQTTUtil implements Serializable, ISTGatewayUtil {
    ...
}

@Stateless
@LocalBean
public class STGatewayWSUtil implements Serializable, ISTGatewayUtil {
    ...
}

您的制作人不需要注入2 Instances<T>。您可以注入两个bean并返回所选择的bean。

public class STGatewayUtilProducer {

    @Produces
    @Chosen
    public ISTGatewayUtil getISTGatewayUtil(STGatewayWSUtil ws, STGatewayMQTTUtil mqtt, ConfigurationManager cm) {
        switch(cm.getGatewayProtocol()) {
            case ConfigurationManager.GATEWAY_PROTOCOL_TYPE_MQTT:
                return mqtt;
            default:
                return ws;
        }
    }

}

或像这样使用Instance<T>

public class STGatewayUtilProducer {

    @Produces
    @Chosen
    public ISTGatewayUtil getISTGatewayUtil(Instance<ISTGatewayUtil> gw, ConfigurationManager cm) {
        switch(cm.getGatewayProtocol()) {
            case ConfigurationManager.GATEWAY_PROTOCOL_TYPE_MQTT:
                return gw.select(STGatewayMQTTUtil.class).get();
            default:
                return gw.select(STGatewayWSUtil.class).get();
        }
    }

}

使用bean实例生成新bean时要小心,它应该具有@Dependent范围(以避免在生成的bean上重叠2生命周期)或者使用@New关键字注入。在这里,您的会话bean位于@Dependent范围内,因为它们没有指定任何范围。

答案 1 :(得分:0)

此处的案例场景非常适用于CDI限定符,如果您需要事务管理,您仍然可以维护ejb会话bean(如果您不需要任何事务逻辑,那么我将首先取消ejbs )。

那就是说,我会设计你的场景:

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

   ISTGatewayType value()

   enum ISTGatewayType {
       MQT,
       WS
   }
}

用法如下所示:(注意ejbs已注释@Dependent以使CDI容器能够自动检测它们。

@Stateless
@Dependent 
@ISTGateway(MQT)
public class STGatewayMQTTUtil implements Serializable, ISTGatewayUtil {
    ...
}

@Stateless
@Dependent
@ISTGateway(WS)
public class STGatewayWSUtil implements Serializable, ISTGatewayUtil {
    ...
}

你的制作人应该是这样的:(关于制作人的好处是你永远不需要更新它,如果你曾经添加新的ISTGatewayUtil)

@ApplicationScoped
public class STGatewayUtilProducer {
    @Any
    @Inject
    private Instance<ISTGatewayUtil> istGatewayUtils;

    @Inject
    private ConfigurationManager configurationManager;

    @Chosen
    @Produces
    public ISTGatewayUtil getISTGatewayUtil() {
        final ISTGateway istGateway = new ISTGatewayImpl(cm.getGatewayProtocol());
        return istGatewayUtils.select(istGateway).get();
    }

    private static final class ISTGatewayImpl extends AnnotationLiteral<ISTGateway> implements ISTGateway {

       private final ISTGatewayType istGatewayType;

       private ISTGatewayImpl( final ISTGatewayType istGatewayType) {
          this.istGatewayType = istGatewayType;
       }

       public ISTGatewayType value() {
           return istGatewayType;
       }
    }  
}