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。因此,我们beans.xml在 data-service-beans 中添加了 a 和@Produces以使(在这种情况下OrganisationAndMandatesRegisterCDI 可注入。想法是未来我们可能会重新打包我们的应用程序并将数据服务与业务服务一起打包在一个企业中档案。

最近我们迁移到 JBOSS EAP7.2(Wildfly 8?),突然间我们看到了各种意想不到的延迟和事务问题。

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

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

4

1 回答 1

3

如果 producer 方法上没有定义范围,则使用 @Dependend,因此请找到适当的范围,也许是 @RequestScoped。当您从 JNDI 检索 EJB 时,您不会获得新的实例,而是从池中获得一个实例,该实例在多次调用中可能是相同的。您的问题可能是 EJB 拦截器,因为如果从属范围内,EJB 实例在注入后始终是相同的,并且永远不会释放。

摆脱@Produces,因为CDI 与EJB 集成,EJB 可以通过@Inject 或@EJB 注入。如果您想保留 Locator 类,那么您可以在其中注入 EJB 并返回正确的 EJB 实例(实际上是一个代理),其中 Locator 应该是 @ApplicationScoped。另一种方法是使用允许程序化查找的实例。使用 Object 类型,您可以访问容器的所有 CDI Bean(包括 EJB),因此公共接口对于最小化可访问 bean 很有用。

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

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

使用 @Inject 将无状态 EJB 注入 CDI Weld ManagedBean(jboss 6 AS 上的 JSF 1.2 EJB 应用程序)

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;
    }
}
于 2019-05-03T17:40:26.793 回答