Java Hibernate具有运行时POJO的OSGi片段包
我的要求是使用hibernate映射各种数据库(特别是SQL Server、MySQl和Postgres);从db记录创建一个xml文件 对于hibernate,我在运行时使用JAssist创建hbm文件和POJO。 我的代码工作得很好,为了进一步模块化,我为每个数据库实现了片段捆绑包。这样,我的主机捆绑包将处理运行时类的创建,并将它们添加到classloader、hbm文件创建逻辑和BL中。fragment通过传递参数来调用它 当我为每个数据库创建一个片段包时, 在主机包中创建的运行时pojo类在片段包中可见, 我检查了“Thread.currentThread().getContextClassLoader().loadClass()” 并能够创建其实例 问题是 当我从fragment bundle调用Hibernate函数时,我得到的是“Entity not mapping”,当Hibernate无法找到带有表的映射类时,会出现这些异常。 所以我想Hibernate没有找到我的运行时pojo类。它可以在主机中找到 主持人: 运行时Pojo创建, HBM和CFG创建和更新逻辑 基本法 片段: 冬眠层, 调用Hibernate函数,Java Hibernate具有运行时POJO的OSGi片段包,java,hibernate,osgi,Java,Hibernate,Osgi,我的要求是使用hibernate映射各种数据库(特别是SQL Server、MySQl和Postgres);从db记录创建一个xml文件 对于hibernate,我在运行时使用JAssist创建hbm文件和POJO。 我的代码工作得很好,为了进一步模块化,我为每个数据库实现了片段捆绑包。这样,我的主机捆绑包将处理运行时类的创建,并将它们添加到classloader、hbm文件创建逻辑和BL中。fragment通过传递参数来调用它 当我为每个数据库创建一个片段包时, 在主机包中创建的运行时pojo
XML创建逻辑如果在多个捆绑包上使用Hibernate,则始终会出现此问题。在Hibernate配置中,您无法分辨在哪个包中可以找到映射文件和pojo类文件。Hibernate不使用OSGI为此提供的机制。因此,hibernate仅查找与hibernate库位于同一捆绑包中的映射文件和类 我不知道是否有专业的解决方案(第三方产品)来解决这个问题 解决此问题有两种可能性:
- 编写自己的类加载器,即使在其他包中也能找到pojo类
- 重写addResource(String resourceName,ClassLoader ClassLoader),以使其也能在其他捆绑包中找到资源
- 重写doConfigure和buildSessionFactory,以便它们使用您的类加载器而不是标准类加载器(使用Thread.setContextClassLoader并从超类(即标准Hibernate配置类)调用该方法)
- 重写所有其他返回配置实例的方法,以便它们返回配置类的实例,而不是Hibernate配置类的实例
我们完成了解决方案2。这是一点工作,但现在运行良好。(我想,当再次更改Hibernate版本时,可能需要做一些工作。)查看org.Hibernate.internal.util.ClassLoaderHelper 您所要做的就是用能够解析实体类的类加载器替换类加载器。 Hibernate Osgi还将其设置为Osgi类加载器(请参见org.Hibernate.Osgi.HibernateBundleActivator)。因此,建议如下:
BundleWideClassLoader cl = new BundleWideClassLoader();
if (ClassLoaderHelper.overridenClassLoader != null
&& ClassLoaderHelper.overridenClassLoader instanceof OsgiClassLoader)
{
OsgiClassLoader ocl = (OsgiClassLoader)ClassLoaderHelper.overridenClassLoader;
for (Bundle b : cl.getBundles()) {
ocl.addBundle(b);
}
} else {
ClassLoaderHelper.overridenClassLoader = new BundleWideClassLoader();
}
我通过重写buildSessionFactory将其放入HibernateConfiguration类,该类执行此例程并返回super.buildSessionFactory
BundleWideClassLoader如下所示
public class BundleWideClassLoader extends ClassLoader
{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
for (BundleClassLoader cl : this.getAllClassLoader()) {
try {
Class clazz = cl.findClass(name);
return clazz;
} catch (Exception ex) {
}
}
throw new ClassNotFoundException(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = this.findClass(name);
if (resolve) {
this.resolveClass(clazz);
}
return clazz;
}
@Override
public URL findResource(String name) {
for (BundleClassLoader cl : this.getAllClassLoader()) {
URL ret = cl.findResource(name);
if (ret != null) {
return ret;
}
}
return null;
}
/**
* Returns a list of all available BundleClassLoader.
*
* @return classloader
*/
public HashSet<BundleClassLoader> getAllClassLoader() {
//
// Do some magic here to get your ClassLoaders from all of your Bundles
//
}
/**
* Returns a list of all bundles which are registered in this BundleWideClassLoader.
*
* @return list of managed bundles
*/
public HashSet<Bundle> getBundles() {
HashSet<Bundle> bundles = new HashSet<>();
for (BundleClassLoader cl : this.getAllClassLoader()) {
bundles.add(cl.getBundleContext().getBundle());
}
return bundles;
}
}
公共类BundleWideClassLoader扩展了ClassLoader
{
@凌驾
受保护类findClass(字符串名称)引发ClassNotFoundException{
对于(BundleClassLoader cl:this.getAllClassLoader()){
试一试{
类clazz=cl.findClass(名称);
回击声;
}捕获(例外情况除外){
}
}
抛出新的ClassNotFoundException(名称);
}
@凌驾
受保护类loadClass(字符串名称,布尔解析)引发ClassNotFoundException{
Class clazz=this.findClass(名称);
如果(解决){
这个类(clazz);
}
回击声;
}
@凌驾
公共URL findResource(字符串名称){
对于(BundleClassLoader cl:this.getAllClassLoader()){
URL ret=cl.findResource(名称);
如果(ret!=null){
返回ret;
}
}
返回null;
}
/**
*返回所有可用BundleClassLoader的列表。
*
*@returnclassloader
*/
公共HashSet getAllClassLoader(){
//
//在这里做一些魔术,从你所有的包中获得你的类加载器
//
}
/**
*返回在此BundleWideClassLoader中注册的所有捆绑包的列表。
*
*@托管捆绑包的返回列表
*/
公共HashSet getBundles(){
HashSet bundles=新的HashSet();
对于(BundleClassLoader cl:this.getAllClassLoader()){
bundles.add(cl.getBundleContext().getBundle());
}
返回包;
}
}
最后是BundleClassLoader:
public class BundleClassLoader extends ClassLoader
{
/**
* Bundle context.
*/
private BundleContext context;
/**
* Constructor.
* @param ctx Bundle Context
*/
public BundleClassLoader(BundleContext ctx) {
this.context = ctx;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return this.context.getBundle().loadClass(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = this.findClass(name);
if (resolve) {
this.resolveClass(clazz);
}
return clazz;
}
@Override
public URL findResource(String name) {
return this.context.getBundle().getResource(name);
}
/**
* Returns bundle context.
* @return bundle context
*/
public BundleContext getBundleContext() {
return this.context;
}
}
公共类BundleClassLoader扩展了ClassLoader
{
/**
*捆绑上下文。
*/
私密文本语境;
/**
*构造器。
*@param ctx Bundle上下文
*/
公共BundleClassLoader(BundleContext ctx){
this.context=ctx;
}
@凌驾
受保护类findClass(字符串名称)引发ClassNotFoundException{
返回此.context.getBundle().loadClass(名称);
}
@凌驾
受保护类loadClass(字符串名称,布尔解析)引发ClassNotFoundException{
Class clazz=this.findClass(名称);
如果(解决){
这个类(clazz);
}
回击声;
}
@凌驾
公共URL findResource(字符串名称){
返回此.context.getBundle().getResource(名称);
}
/**
*返回绑定上下文。
*@returnbundle上下文
*/
public BundleContext getBundleContext(){
返回这个.context;
}
}
我建议在每个外滩都创建一个新的BundleClassLoader