OSGi中Envers的类加载器问题

OSGi中Envers的类加载器问题,osgi,hibernate-envers,Osgi,Hibernate Envers,我已经在OSGi上下文中成功地启动了Hibernate,现在我想添加Envers 这是可能的。我再也不相信了。没有任何关于这个主题的文档,而且似乎没有人真正做过。此外,即使使用Blueprint实现,我也必须破解类加载器,使Hibernate甚至可以找到Envers: osgiClassLoader = new org.hibernate.osgi.OsgiClassLoader(); osgiClassLoader.addBundle(requestingBundle); osgiClassL

我已经在OSGi上下文中成功地启动了Hibernate,现在我想添加Envers

这是可能的。我再也不相信了。没有任何关于这个主题的文档,而且似乎没有人真正做过。此外,即使使用Blueprint实现,我也必须破解类加载器,使Hibernate甚至可以找到Envers:

osgiClassLoader = new org.hibernate.osgi.OsgiClassLoader();
osgiClassLoader.addBundle(requestingBundle);
osgiClassLoader.addBundle(FrameworkUtil.getBundle(SessionFactory.class));
osgiClassLoader.addBundle(FrameworkUtil.getBundle(HibernateEntityManagerFactory.class));
osgiClassLoader.addBundle(FrameworkUtil.getBundle(EnversService.class));

Thread.currentThread().setContextClassLoader(osgiClassLoader);
(我觉得我应该问:“OSGi中的Envers可能吗?”所以如果你对这个问题有明确的答案,请让我知道。我在这些问题上花了太多时间。)

然而,实际问题与Hibernate/Envers无关,而与OSGi无关。两者都希望访问所使用的实体和枚举。尽管如此,我还是反思了一下。他们当然不能。当然,我不能添加导入包

相关堆栈跟踪如下所示:

Caused by: java.lang.ClassNotFoundException: org.acme.project.MyEnum cannot be found by org.hibernate.core_5.1.0.Final
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:461)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
    at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:151)
    at org.hibernate.type.EnumType.setParameterValues(EnumType.java:105)
    ... 62 more
通常,对于OSGi不可知框架,我会在MANIFEST.MF中添加如下内容:

但是,我无法向Hibernate的清单中添加任何内容。我试图通过片段贡献这一行,但也不起作用

我甚至尝试将整个Hibernate依赖项作为JAR添加到插件中,以添加上述内容。这行不通


如何解决这些类加载器问题?

如果@Audited类引用枚举,org.hibernate.core需要导入类包。最好的方法是注册一个片段包

此外,明智的做法是确保hibernate捆绑包的开始级别低于实体捆绑包的开始级别

下面是一个示例Gradle脚本的片段,用于创建片段束。确保将org.hibernate.core捆绑包版本更改为您正在使用的版本,并将“your.package”更新为包含枚举的版本

/*
When using Envers, entities that reference Enum classes must be imported (Import-Package) by the org.hibernate.core bundle.
 */

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:3.2.0'
    }
}

apply plugin: 'biz.aQute.bnd.builder'

jar {
    manifest {
        attributes(
                'Fragment-Host': 'org.hibernate.core;' + 'bundle-version=' + '5.2.9.Final',
                'Import-Package': 'your.package'
        )
    }
}

如果@Audited类引用枚举,org.hibernate.core需要导入classes包。最好的方法是注册一个片段包

此外,明智的做法是确保hibernate捆绑包的开始级别低于实体捆绑包的开始级别

下面是一个示例Gradle脚本的片段,用于创建片段束。确保将org.hibernate.core捆绑包版本更改为您正在使用的版本,并将“your.package”更新为包含枚举的版本

/*
When using Envers, entities that reference Enum classes must be imported (Import-Package) by the org.hibernate.core bundle.
 */

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:3.2.0'
    }
}

apply plugin: 'biz.aQute.bnd.builder'

jar {
    manifest {
        attributes(
                'Fragment-Host': 'org.hibernate.core;' + 'bundle-version=' + '5.2.9.Final',
                'Import-Package': 'your.package'
        )
    }
}

派对迟到了,但把这个扔到这里以防其他人需要它:

Hibernate引导在OSGi中看起来与在SE/EE领域中完全不同。我们在JIRA跟踪增强中有很多功能,特别是为了使事情更具动态性和减少启动顺序的脆弱性(Steven绝对正确,hibernate core、hibernate envers等当前必须在捆绑之前首先启动)

我强烈建议不要使用bundle片段方法,但我将对Steven的回答中的原因进行评论


我们的hibernate演示项目有几个OSGi快速入门,所有这些都包括Envers设置。这一个可能更符合你的要求:

派对迟到了,但把它扔到这里,以防其他人需要它:

Hibernate引导在OSGi中看起来与在SE/EE领域中完全不同。我们在JIRA跟踪增强中有很多功能,特别是为了使事情更具动态性和减少启动顺序的脆弱性(Steven绝对正确,hibernate core、hibernate envers等当前必须在捆绑之前首先启动)

我强烈建议不要使用bundle片段方法,但我将对Steven的回答中的原因进行评论


我们的hibernate演示项目有几个OSGi快速入门,所有这些都包括Envers设置。这一个可能更符合您的要求:

您是否尝试导出包org.acme.project?@isco它已导出。但是,
org.hibernate.core
无法导入它。嗯,您的hibernate模块,它们是作为捆绑包部署还是嵌入的?对于包含MyEnum的模块,同样的问题?@isco包含MyEnum的模块是一个常规的旧包。对于Hibernate,我尝试了这两种方法。根据规范(osgi§3.14),应该可以使用片段包将所需的导入定义添加到org.Hibernate.core。我自己从来没有尝试过。你尝试过导出包org.acme.project吗?@isco它被导出了。但是,
org.hibernate.core
无法导入它。嗯,您的hibernate模块,它们是作为捆绑包部署还是嵌入的?对于包含MyEnum的模块,同样的问题?@isco包含MyEnum的模块是一个常规的旧包。对于Hibernate,我尝试了这两种方法。根据规范(osgi§3.14),应该可以使用片段包将所需的导入定义添加到org.Hibernate.core。我自己从来没有试过。一般来说,像瘟疫一样应该避免捆绑碎片,在这种情况下,它实际上是不必要的。关于启动顺序,你是绝对正确的。但更进一步的是:如果Hibernate ORM使用适当的OSGi引导(我将在单独的答案中提供详细信息),我们已经完全可以看到客户机/持久性捆绑包(我们将捆绑包的类加载器添加到整个Hibernate本身使用的聚合类加载器中)。如果跳过该引导,您将开始看到这些类型的错误。通常,应该像瘟疫一样避免捆绑包碎片,在这种情况下,它实际上是不必要的。关于启动顺序,你是绝对正确的。但更进一步的是:如果Hibernate ORM使用适当的OSGi引导(我将在单独的答案中提供详细信息),我们已经完全可以看到客户机/持久性捆绑包(我们将捆绑包的类加载器添加到整个Hibernate本身使用的聚合类加载器中)。如果跳过该引导,您将开始看到这些类型的错误。那么,根据我的示例,具体是什么创建了导入枚举的“引导”?它是POM中的手动输入之一吗?