【问题标题】:JDO PersistenceManager injection to GlassFish 4 Jersey 2 RESTful web applicationJDO PersistenceManager 注入 GlassFish 4 Jersey 2 RESTful Web 应用程序
【发布时间】:2013-08-17 23:45:21
【问题描述】:

我正在寻找基于 JAX-RS / Jersey 2 和 EJB 3.1 Lite 将 JDO PersistenceManager 和/或 PersistenceManagerFactory 注入(或以其他方式最佳初始化)到 RESTful Web 应用程序资源的最干净的方法,最好不添加太多额外的依赖。该项目使用 DataNucleus 并使用 Maven 3 构建。

以下是我找到的一些提示。也许您已经尝试过其中一些方法并发现哪种方法效果最好:

当前的解决方案是基于 JPA 的,注入工作照常进行。以下代码已被简化,遗憾的是我无法发布原始代码。

main/java/project/ws/rs/TestResource.java:

@Path("/test")
@Stateless
public class TestResource {

    @PersistenceContext(unitName = "project-webapi")
    private EntityManager em;

    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@PathParam("id") UUID id) {
        return Response.status(
                Response.Status.OK).entity(em.find(type, id)).build();
    }
}

正如您在上面看到的,持久的 JAX-RS 资源被注释为 @Stateless EJB's。

我的目标平台 GlassFish 4.0 提供了所有 Java EE 和 Jersey 依赖项。 DataNucleus 库包含在WEB-INF/lib 中的运行时可部署战争工件中。

该项目有一个由main/resources/META-INF/persistence.xml 文件描述的标准持久性单元。

<persistence>
  <persistence-unit name="project-webapi"/>
</persistence>

(为简单起见,省略了 XML 命名空间和模式引用。)

部署描述符在main/webapp/WEB-INF/web.xml:

<web-app version="3.0" metadata-complete="false" />

目标

我想从 JPA 切换到 JDO,而不会像上面那样丢失干净的依赖注入。理想的解决方案当然类似于将EntityManager 替换为上面的PersistenceManager,但是如何实现这一点,或者可能有更好的方法?如果其他方法对此目的更有效,则不必注入。

我切换的原因是能够在 DataNucleus 的帮助下使用非 SQL 持久性,并为我的 Java EE Web 应用程序提供完整的 ORM 实现。

我相信还有很多其他人对此感兴趣。有什么想法吗?

编辑:为上述网络应用寻找最有效的方法来获取对 PersistenceManager 的引用是这个问题的重点。

使用 JPA,它是通过注入完成的。显然,我们知道 Java EE 规范和应用服务器不直接通过 JDO 支持这一点。否则我们不会问这个。因此,我们追求最简洁和“最可部署”的方式来为 Web 应用程序做这件事。

【问题讨论】:

  • 我没用过这个,你有想过用这个吗? datanucleus.org/products/accessplatform_3_3/rest/api.html
  • @MuhammadGelbana,谢谢。我确实扫描了它,但这也是一个普遍的问题。在某些情况下,访问平台对我有用,但在其他情况下,我需要更多的手动控制。也许我正在寻找的答案在来源中的某个地方。一旦我可以花更多时间在这方面,我将继续研究,但现在我必须继续使用 JPA。同时,如果有人已经给出了可以为我们所有人节省时间的答案。
  • 在 JDO 中没有 PersistenceContext/PersistenceUnit 注入,因为它依赖于实现它的 JavaEE 服务器(这不是 DataNucleus JPA 的一部分......它在 Glassfish/JBoss 等中)。 JDO 没有具体说明容器的作用,因为政界人士规定不允许这样做(除了使用 JCA 允许在容器中使用)。 “容器”必须进行注入......所以看看 Spring 或 Guice 是你最好的选择
  • @DataNucleus 非常感谢您的宝贵时间和专家意见。

标签: jakarta-ee jax-rs jdo datanucleus glassfish-4


【解决方案1】:

我使用 CDI 拦截器在我们的 Web 应用程序中创建和拆除 JDO PM。

您可以在帮助类中定义依赖于 ThreadLocal 的拦截器方法。我在这里简化了我的代码(阅读:未经测试:)),因为您可能必须处理多个数据源、重新输入等,但如图所示:

public class MyJDO_Helper {

    private static ThreadLocal<PersistenceManager> localPM = new ThreadLocal<>();

    @AroundInvoke
    public Object allocatePersistenceManager(InvocationContext ctx) throws Exception {
        PersistenceManager pm = localPM.get();
        if (pm == null) {
            pm = getNewPersistenceManager();
            localPM.set(pm);
        }
        try {
            return ctx.proceed();
        }
        catch(Error err) { // to log them before Jersey blows casting them to Ex
            log.log(Level.SEVERE, "Caught " + err, err);
            throw err;
        }
        finally {
            try {
                if (pm.currentTransaction().isActive()) {
                    pm.currentTransaction().rollback();
                }
                pm.close();   
            }
            catch(Exception ex) {
                log.log(Level.SEVERE, "Error closing JDO PM: " + ex, ex);
            }
        }
    }

    public static PersistenceManager getPersistenceManager() {
        return localPM.get();
    }

然后你可以在需要 JDO 访问的 Jersey 资源方法上贴上这个拦截器:

@ManagedBean // for interceptors
@Path("/my")
public class MyResource {

    @GET
    @Interceptors({MyJDO_Helper.class})
    public String get() {
        PersistenceManager pm = MyJDO_Helper.getPersistenceManager();

此时,您可以随时从代码中的任何位置(甚至不是 Jersey 类)调用 MyJDO_Helper.getPersistenceManager(),并且您将始终获得正确的 PM,而无需传递它。 :)

【讨论】:

  • 当我有时间回到这里时,我需要为此仔细研究 CDI。感谢您的指点,@TheArchitect。一旦我有机会在实践中测试它,我会确认它。
猜你喜欢
  • 2015-08-03
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多