l 解决和hibernate的集成
传统方式下,hibernate通过hibernate.cfg.xml中的mapping resource来加载归入sessionfactory中的管理得po,加载过程中,hibernate通过hibernate类所在的classloader加载mapping resource中配置的hbm映射文件,并通过cglib将hbm映射文件中指定的class生成proxy.
基于osgi的系统后,产生了以下两个冲突:
1. po分散到不同的工程了,同时要保持模块的封装性,就不能所有人都修改hibernate模块里的hibernate.cfg.xml文件。
2. 封装hibernate的模块的classloader无法加载到其他模块的po对象。
解决以上冲突时基于osgi使用hibernate的关键,需要解决的就是如何将其他模块的po注册到封装hibernate的模块中,及hibernate的configuration如何加载其他模块的po和映射文件。方案如下:
增加扩展点方式可以实现。之后需要的是把class加入到hibernate的configuration中,osgi中每个bundle都是独立的classloader,hibernate所在的bundle无法加载到扩展点中classname所对应的类,,但在实现扩展点的模块中创建提供扩展的类可以实现。
这是我们目前实现的方式,通过标准的Eclipse扩展点与扩展机制,我们在Hibernate插件中plugin.xml配置文件中声明下述扩展点:
<extension-point id="org.opengoss.database.domain.object" name="domainObject"/>
在模型对象插件中声明扩展,例如:
<extension point="org.opengoss.database.domain.object">
<domainObject class="org.opengoss.alarm.core.Alarm"/>
</extension>
Hibernate插件的启动中,用代码配置生成SessionFactory,代码如下:
props.put("uid", "Hibernate:SessionFactory"); public void start(BundleContext context) throws Exception {
Configuration configuration = new Configuration().configure(new File(
"./etc/org.opengoss.database.hibernate/hibernate.cfg.xml"));
Class[] domainClasses = getDomainClasses();
for (Class domainClass : domainClasses) {
configuration.addClass(domainClass);
}
sessionFactory = configuration.buildSessionFactory();
Dictionarynew Hashtable
props.put("scope", "APPLICATION");
registration = context.registerService( SessionFactory.class.getName(), sessionFactory, props);
}
private Class[] getDomainClasses() throws Exception {
List domainClasses = new ArrayList();
IExtensionPoint point = registry .getExtensionPoint(IConstants.DOMAIN_OBJECT_EXTENSION_POINT);
IExtension[] extensions = point.getExtensions();
for (IExtension extension : extensions) {
IConfigurationElement[] elements = extension .getConfigurationElements();
for (IConfigurationElement configurationElement : elements) {
Bundle bundle = pluginContext.getBundleBySymbolId(extension .getNamespaceIdentifier());
Class domainClass = bundle.loadClass(configurationElement .getAttribute("class"));
domainClasses.add(domainClass);
}
}
return domainClasses.toArray(new Class[domainClasses.size()]);
}注意:Hibernate内部的类加载机制实在无法令人满意,尽管我们在这种方式中已经加载所有的模型类对象,但Hibernate内部仍然会调用Class.forName()去试图加载。所以,我们不得不在其自描述文件(MANIFEST.MF) 中加入描述:
DynamicImport-Package: *
u 再这里通过一个基于osgi加入hibernate支持的具体事例来分析开发具体细节与流程:
(基于一个图书查询的实现,关于一些bundle的配置(hibernate,spring,mysql等)
l 准备Hibernate Bundle
在运行时hibernate需要如下的库:(本文档实例中包的具体版本根据需求导入)
asm.jar
asm-attrs.jar
cglib-2.1.3.jar
dom4j-1.6.1.jar
antlr-2.7.6.jar
这些库都可以在hibernate下载包中的lib目录里找到。为了简单起见,我们把这些库放到hibernate Bundle里,而不把每个库打成单独的bundle。
因为在执行过程中会出现了一个错误:
java.lang.NoClassDefFoundError:org/hibernate/proxy/HibernateProxy