Datanucleus、JDO 和可执行 jar - 怎么做?

Posted

技术标签:

【中文标题】Datanucleus、JDO 和可执行 jar - 怎么做?【英文标题】:Datanucleus, JDO and executable jar - how to do it? 【发布时间】:2012-04-23 05:12:25 【问题描述】:

我正在使用 Datanucleus 和 JDO 为嵌入式 H2 数据库开发桌面应用程序。当我从 Eclipse 运行它时一切正常,但是当我尝试从中制作可执行 jar 时它停止工作。我收到以下错误:

org.datanucleus.exceptions.NucleusUserException:已指定持久化进程使用名称为“jdo”的 ClassLoaderResolver,但 DataNucleus 插件机制尚未发现此问题。请检查您的 CLASSPATH 和插件规范。

当然这表明我没有正确配置一些东西——我错过了什么?如果我遗漏了一些大的东西,它根本就不起作用,所以我假设它是一个有缺陷的可执行 jar。我在其他应用程序(例如 JPOX)中看到了该错误,该错误已得到修复,但没有给出任何解决方案。

整个错误堆栈跟踪:

Exception in thread "main" javax.jdo.JDOFatalInternalException: Unexpected exception caught.
        at javax.jdo.JDOHelper.invokeGetPersistenceManagerFactoryOnImplementation(JDOHelper.java:1193)
        at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:808)
        at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:701)
        at db.PersistenceManagerFilter.init(PersistenceManagerFilter.java:44)
        at Main.main(Main.java:26)
NestedThrowablesStackTrace:
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at javax.jdo.JDOHelper$16.run(JDOHelper.java:1965)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.jdo.JDOHelper.invoke(JDOHelper.java:1960)
        at javax.jdo.JDOHelper.invokeGetPersistenceManagerFactoryOnImplementation(JDOHelper.java:1166)
        at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:808)
        at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:701)
        at db.PersistenceManagerFilter.init(PersistenceManagerFilter.java:44)
        at Main.main(Main.java:26)
Caused by: org.datanucleus.exceptions.NucleusUserException: Persistence process has been specified to use a ClassLoaderResolver of name "jdo" yet this has not been found by the DataNucleus plugin mechanism. Please check your CLASSPATH and plugin specification.
        at org.datanucleus.NucleusContext.<init>(NucleusContext.java:233)
        at org.datanucleus.NucleusContext.<init>(NucleusContext.java:196)
        at org.datanucleus.NucleusContext.<init>(NucleusContext.java:174)
        at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.<init>(JDOPersistenceManagerFactory.java:364)
        at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.createPersistenceManagerFactory(JDOPersistenceManagerFactory.java:294)
        at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.getPersistenceManagerFactory(JDOPersistenceManagerFactory.java:195)
        ... 12 more

它指向的行是PersistenceManagerFilter init方法:

pmf = JDOHelper.getPersistenceManagerFactory(getProperties());

属性文件如下所示:

    javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.api.jdo.JDOPersistenceManagerFactory
datanucleus.ConnectionDriverName=org.h2.Driver
datanucleus.ConnectionURL=jdbc:h2:datanucleus
datanucleus.ConnectionUserName=sa
datanucleus.ConnectionPassword=

我拥有来自 maven 的所有依赖项,目标是使用依赖项进行部署。依赖关系如datanucleus页面http://www.datanucleus.org/products/datanucleus/jdo/maven.html

所述

有什么想法吗?

【问题讨论】:

什么“可执行jar”?由什么组成? 具有 maven 依赖项的整个项目部署为可执行 jar 文件。 你的意思是你解开了 DN 罐子,把所有东西都放在一个罐子里? 我已经把所有东西都打包到了大 jar 中,所有的依赖 jar 都打包到了可执行的 jar 中。在 jar 中使用 maven-repo 样式结构用于依赖项。捆绑所有内容的正确方法是什么,这样我就可以拥有工作 jar,并且所有依赖项都正常工作? 不,我的清单文件中没有。我不是在创建一个插件,只是一个独立的 java 应用程序,所以我没有看那部分文档。我真的不知道该放什么,捆绑信息,还是只定义导入? 【参考方案1】:

DataNucleus jars 都支持 OSGi 并使用插件机制来识别功能,因此包含 plugin.xmlMETA-INF/MANIFEST.MF 文件。这些需要位于与原始 DN jar 相同的位置(从 jar 的根目录)。如果您解压缩然后重新打开它们,您将需要从 DN jar 中合并任何 plugin.xml 和 META-INF/MANIFEST.MF ...所有信息,而不仅仅是其中的一些信息。

【讨论】:

好的,我现在很确定我的 jar 是正确的并且包含所有必需的信息。我想我在属性中遗漏了一些东西,它会是什么?或者他们是正确的?我已经编辑了我的帖子以包含所有属性。可能是关于缺少 datanucleus.ConnectionFactoryName 吗?它应该有什么价值? 您能否更准确地了解合并这些文件的方法?不明显。 @DataNucleus 是的,解释合并清单文件的最佳/正确方法会很棒。我在一个大项目中编译了一个带阴影的 JAR,需要手动合并的东西太多了 @jtravaglini。 MANIFEST 信息是 OSGi,因此任何 OSGi 资源都应该在这方面为您提供帮助(DataNucleus 不会明确使用它,并且当您在 AFAIK 中出现一些错误时不会停止工作)。 plugin.xml 应该很明显如何合并(作为一个 XML 文件)......将所有扩展点放在顶部(从所有被合并的 plugin.xml 文件中),然后将所有扩展放在下面(以及每个扩展的所有条目一起扩展)。【参考方案2】:

添加到 DataNucleus 答案。 为了达到你所需要的,你应该使用 ma​​ven-dependency-plugin 并将以下内容添加到您的 pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.4</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>$project.build.directory/jars</outputDirectory>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

然后依赖项将在 target/jars 目录中。 要执行您的应用,请使用命令: Windows:java -cp "yourFile.jar;jars/*" package.className Linux:java -cp "yourFile.jar:jars/*" package.className 注意:不要使用 jars/*.jar,这不起作用

【讨论】:

【参考方案3】:

为了在需要单个 jar 的 Apache Storm 拓扑中使用 DataNucleus 4.x,我必须进行两次 hack 以保持他们的 PluginRegistry 工作正常。问题是 DataNucleus 核心尝试将模块加载为 OSGi 包,即使它没有在 OSGi 容器中运行。只要 jar 没有被合并,它就可以正常工作(我不想合并我的依赖项,但这不是我的选择)。

首先,我将所有 plugin.xml 文件合并到 datanucleus-core plugin.xml 中。诀窍是扩展点 id 是相对于其父插件的 id 的。因此,如果您正在使用的任何模块定义新的扩展点,例如datanucleus-rdbms,您必须重写 id,以便它们与新的父插件相关。

其次,我在 jar 的 MANIFEST.MF 中添加了以下条目:

Premain-Class: org.datanucleus.enhancer.DataNucleusClassFileTransformer
Bundle-SymbolicName: org.datanucleus;singleton:=true

这个解决方案并不理想,因为我们的应用程序本质上是在伪装成 DataNucleus 核心 OSGi 包。然而,这就是我在休息几天后把头砸在桌子上的结果。

也许可以提供不同的 PluginRegistry 实现,但我没有对此进行研究。

【讨论】:

你能解释一下哪些ID吗?【参考方案4】:

对于其他努力合并 datanucleus plugin.xml 文件的人,我使用以下代码提供帮助。使用此命令从 3 个单独的 datanucleus plugin.xml 文件中传输内容,这将告诉您哪里有明确需要合并的扩展:

cat plugin_core.xml plugin_rdbms.xml plugin_api.xml | grep -h "extension point" | tr -d "[:blank:]"| sort | uniq -d

更多详情请见separate post。

【讨论】:

以上是关于Datanucleus、JDO 和可执行 jar - 怎么做?的主要内容,如果未能解决你的问题,请参考以下文章

Class org.datanucleus.api.jdo.JDOPersistenceManagerFactory was not found

未找到类 org.datanucleus.api.jdo.PersistenceManagerFactoryClass

Datanucleus/JDO,持久化和检索 java.util.Set 属性

如何在GlassFish上部署基于JDO的EAR文件?

AWS Beanstalk 与 DataNucleus 的 RDS 问题

Datanucleus:从@Transactional 迁移到非事务性