0

我正在尝试在具有尽可能多的模块化的 OSGi 环境(运行 Felix 的 Karaf)中进行持久性。我选择 JDO 是因为它的附加功能(主要是获取组)而不是 JPA。实现是 Datanucleus。我使用 Maven 来构建整个项目。

由于我之前没有任何使用 JDO 或 OSGi 的经验,因此要让它们中的任何一个工作起来都是一个相当大的挑战。我目前能够在 Java SE 环境中进行 JDO 持久性(单元测试工作没有问题),并且我知道如何使用蓝图容器在 OSGi 环境中提供服务。但我无法让这两件事一起工作。我遇到类加载问题。

我什至无法构建一个能够在 Karaf 上执行 JDO 持久性的简单应用程序(我尝试按照本教程进行操作,但它使用了 Spring DM,我无法将其重写为使用 OSGi 蓝图)。

我最困惑的是:

  • 我应该将datanucleus.primaryClassLoader属性设置为什么值?
  • 什么类加载器作为参数传递给JDOHelper.getPersistenceManagerFactory方法?
  • 使用maven-bundle-plugin显式导入哪些包?(看起来至少可能需要javax.jdoorg.datanucleus.api.jdoorg.osgi.framework )
  • 除了对PersistenceManagerFactory的引用之外,其他包还需要什么?

此外:

  • 是否可以将持久性信息与值类分开?如果我理解正确,那只有在使用运行时增强时才有可能,如果完全可行的话,这将非常复杂。
  • 是否可以在多个包中定义相互依赖的持久性类?比如在一个包中定义用户,在另一个包中定义他们的地址?

我将非常感谢一个简单的多捆绑项目示例,该项目仅使用 Datanucleus、JDO API 和 OSGi 蓝图来处理持久性。

谢谢

4

1 回答 1

0

我只能提供一些关于让 JDO/datanucleus 在 Karaf 之上工作的基本提示。

正如教程中所指出的,您需要扩展LocalPersistenceManagerFactoryBean、实现BundleContextAware接口。

这里的关键点是类加载:LocalPersistenceManagerFactoryBean期望所有类都由一个类加载器加载,而在 OSGi 运行时中并非如此。

为了让它工作,你需要:

  1. org.datanucleus.api.jdo在清单文件中显式导入。
  2. datanucleus.primaryClassLoader属性可以设置为您将传递给该JDOHelper.getPersistenceManagerFactory方法的相同类加载器。类加载器是org.datanucleus.api.jdo包使用的类加载器(参见下面的示例)
  3. 您需要将datanucleus.plugin.pluginRegistryClassName属性设置为org.datanucleus.plugin.OSGiPluginRegistry.
  4. 停止/卸载捆绑包时,您必须刷新javax.jdo捆绑包以避免在重新创建持久性管理器工厂时出现错误(检查这个问题的主题)

示例自定义 LocalPersistenceManagerFactoryBean:

public class OSGiLocalPersistenceManagerFactoryBean
    extends LocalPersistenceManagerFactoryBean implements BundleContextAware {

    public static final String JDO_BUNDLE_NAME    = "org.datanucleus.api.jdo";
    public static final String JDO_PMF_CLASS_NAME = "org.datanucleus.api.jdo.JDOPersistenceManagerFactory";

    private BundleContext bundleContext;

    @Override
    protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
        return JDOHelper.getPersistenceManagerFactory(name, getClassLoader());
    }

    @Override
    protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
        ClassLoader classLoader = getClassLoader();

        props.put("datanucleus.primaryClassLoader", classLoader);

        if (FrameworkUtil.getBundle(this.getClass()) != null) { // running in OSGi
            props.put("datanucleus.plugin.pluginRegistryClassName", "org.datanucleus.plugin.OSGiPluginRegistry");
        }

        PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props, classLoader);

        return pmf;
    }

    private ClassLoader getClassLoader() {
        ClassLoader classLoader = null;
        Bundle thisBundle = FrameworkUtil.getBundle(this.getClass());

        if (thisBundle != null) { // on OSGi runtime
            Bundle[] bundles = bundleContext.getBundles();

            for (Bundle bundle : bundles) {
                if (JDO_BUNDLE_NAME.equals(bundle.getSymbolicName())) {
                    try {
                        classLoader = bundle.loadClass(JDO_PMF_CLASS_NAME).getClassLoader();
                    } catch (ClassNotFoundException e) {
                        // do something fancy here ...
                    }
                    break;
                }
            }
        } else { // on Java runtime
            classLoader = this.getClass().getClassLoader();
        }
        return classLoader;
    }

    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
}
于 2013-10-24T12:12:31.310 回答