集成EJB(JNDI)和CDI的最佳方法

时间:2019-04-17 07:00:58

标签: java-ee cdi jndi ejb-3.2

当前,我们拥有一个部署体系结构,一堆面向数据的服务通过RMI暴露给业务服务。两种类型(面向数据的服务和业务服务)都是无状态会话Bean。每个数据服务接口包(包含远程接口)也都有一个定位器,该定位器执行JNDI查找。我们这样做是为了可以在业务服务逻辑中的任何地方调用面向数据的服务。

这是定位器的外观:

public final class OMRLocator {

    private static final Logger LOG = Logger.getLogger( OMRLocator.class );

    private static final String ORG_WILDFLY_INITIAL_CTX_FACTORY = "org.wildfly.naming.client.WildFlyInitialContextFactory";

    private OMRLocator() {
    }

    @Produces
    public static OrganisationsAndMandatesRegister locate() {
        try {
            Properties ctxProp = new Properties();
            ctxProp.put( Context.INITIAL_CONTEXT_FACTORY, ORG_WILDFLY_INITIAL_CTX_FACTORY );
            InitialContext ctx = new InitialContext( ctxProp );
            return (OrganisationsAndMandatesRegister) ctx.lookup( OrganisationsAndMandatesConstants.REMOTE_NAME );
        }
        catch ( NamingException ex ) {
            LOG.log( Level.WARN, "Cannot reach: " + OrganisationsAndMandatesConstants.REMOTE_NAME, ex );
            return null;
        }
    }
}

我们在JBOSS EAP6上运行,并开始尝试CDI。因此,我们在data-service-bean和beans.xml中添加了@Produces,以使(在这种情况下,OrganisationAndMandatesRegister CDI可注入。这种想法是,将来我们可能会重新打包应用程序并将数据服务与业务服务打包到一个企业档案中。

最近我们迁移到JBOSS EAP7.2(Wildfly 8?),突然我们发现各种意外的延迟和事务问题。

我怀疑我们获取豆子的方式是这些问题的一个因素。例如:我认为范围取决于业务EJB生命周期,但是对于业务服务中对locate()的每次调用,都会产生一个新的数据服务实例。

那么:使用CDI时(通过RMI)产生远程bean的最佳方法是什么?鉴于两种服务都是无状态的(或者这是自动完成的),我应该考虑范围吗?

1 个答案:

答案 0 :(得分:2)

如果在生产者方法上未定义范围,则使用@Dependend,因此请找到适当的范围,也许是@RequestScoped。从JNDI检索EJB时,不会得到新的实例,而是从池中获得一个实例,该实例在多个调用中可能是相同的。您的问题可能是EJB拦截器,因为如果从属作用域限定了范围,则EJB实例一旦注入就永远是相同的。

摆脱@Produces,因为CDI与EJB集成,并且可以通过@Inject或@EJB注入EJB。如果要保留Locator类,则可以在其中注入EJB并返回适当的EJB实例(实际上是代理),从而Locator应该是@ApplicationScoped。另一种方法是使用允许程序化查找的实例。使用对象类型,您可以访问容器的所有CDI Bean(包括EJB),因此公共接口将有助于最大程度地减少可访问的Bean。

请参阅以下链接以获取更多帮助。

https://docs.jboss.org/weld/reference/latest/en-US/html/injection.html#_obtaining_a_contextual_instance_by_programmatic_lookup

Inject a stateless EJB with @Inject into CDI Weld ManagedBean (JSF 1.2 EJB Application on jboss 6 AS)

http://www.adam-bien.com/roller/abien/entry/inject_vs_ejb


总结一下:

选项a)保持原样。也许用@Dependent来使作用域明确,以表明这是在调用bean创建(调用bean的构造函数中注入)时调用的。

选项b)使用无状态的@ApplicationScoped会话bean

@LocalBean // otherwise @EJB will not work
@ApplicationScoped // this instance should be created only once per ear
public class OMRLocator {

    @EJB // does implicitly a remote (default) JNDI lookup
    private OrganisationsAndMandatesRegister instance;

    @Produces
    @Dependent // just to make it explicit
    public OrganisationsAndMandatesRegister locate() {
       return instance;
    }
}