我正在尝试在尽可能多的模块化的OSGi环境(运行Felix的Karaf)中进行持久化。我选择JDO作为其附加功能(主要是获取组)而不是JPA。实施是Datanucleus。我使用Maven来构建整个项目。
由于我之前没有任何JDO或OSGi的经验,因此让它们中的任何一个工作都是一个相当大的挑战。我现在能够在Java SE环境中进行JDO持久化(单元测试工作没有问题),我知道如何使用蓝图容器在OSGi环境中提供服务。但我无法让这两件事情协同工作。我正在加载类加载问题。
我甚至无法构建一个能够在Karaf上执行JDO持久化的简单应用程序(我尝试了this tutorial但它使用了Spring DM而我无法重写它以使用OSGi蓝图代替)
我最困惑的是:
此外:
我非常感谢一个简单的多包项目的例子,它只使用Datanucleus,JDO API和OSGi蓝图来处理持久性。
谢谢
答案 0 :(得分:0)
我只能提供一些关于让JDO / datanucleus在Karaf上工作的基本提示。
正如教程中所指出的,您需要扩展LocalPersistenceManagerFactoryBean
,同时实现BundleContextAware
接口。
这里的关键点是类加载:LocalPersistenceManagerFactoryBean
期望所有类都由一个类加载器加载,而在OSGi运行时则不是这样。
为了让它运转起来,你需要:
org.datanucleus.api.jdo
。datanucleus.primaryClassLoader
属性可以设置为您传递给JDOHelper.getPersistenceManagerFactory
方法的同一个类加载器。类加载器是org.datanucleus.api.jdo
包使用的类(参见下面的示例)datanucleus.plugin.pluginRegistryClassName
属性设置为org.datanucleus.plugin.OSGiPluginRegistry
。javax.jdo
捆绑包以避免在重新创建持久性管理器工厂时出现错误(检查主题上的this question)示例自定义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;
}
}