1

我开发了一个库,该库在给定抽象类中的某些注释的情况下在运行时生成抽象类的特化类。所以我的图书馆有点像:

X x = newInstance(X.class) //X is an abstract class

该库使用 Javassist 在运行时生成将由该newInstance方法实例化的子类。

据我了解,Hibernate 还利用 Javassist 在运行时实体类进行检测(如果不是这种情况,请有人纠正我)。

我的问题是是否有可能使这两个框架一起工作?我的意思是,我可以告诉 Hibernate 每次它需要一个实体类(一个抽象类)的实例时,它应该使用我的库中的特定工厂方法吗?

我不知道 Hibernate 是否通过在实体类的运行时生成子类(假设 Hibernate 也需要对它们进行检测)来支持 Courtains。如果是这种情况,将某些类的工厂传递给 Hibernate 的解决方案将不起作用。在那种情况下,Hibernate 是否支持使用抽象实体类?我的意思是,应该可以使用抽象(或接口?)实体类,并以某种方式告诉 Hibernate,当需要使用这些抽象实体类之一时,它应该检测哪个是正确的具体类。

但另一个复杂之处在于,在编译时不存在专门化抽象实体类的具体类。

4

1 回答 1

4

在前往您的回答之前:

  • 是的,你是对的,Hibernate 目前使用 Javassist(过去它使用 GCLib,但它已被弃用)在运行时检测类。
  • Hibernate 确实会在运行时创建子类,这些子类可以为您的持久实体提供代理。

简短的回答

遗憾的是,我认为您无法将 Hibernate 配置为使用您自己的工厂。有关详细信息,我邀请您阅读长答案部分。

长答案

据我所知,目前,Hibernate 4.x 仅支持 Javassist 作为其字节码操作提供程序。虽然,它曾经允许您在 3.x 版本中在 GClib 和 Javassist 之间切换。回到那些版本,您可以通过配置名为hibernate.bytecode.provider.

此设置不再显示在Hibernate 4.1 文档中,但您仍然可以在可选配置属性下的 Hibernate 3.2 文档中找到有关它的信息。

作为一名开发人员,我知道有时我们是一些棘手的人,仅仅因为某些东西不在文档中并不意味着它一定不在代码中 :-) 所以,我认为如果设置仍然存在,我们可以尝试利用它是为了做你想做的事(不过,以不受支持的方式)。

出于好奇,因为我的机器中有 Hibernate 4.0.1 代码(但请注意这不是最新的),我做了一些挖掘......而且惊喜,惊喜财产仍然存在!在跟踪使用过的引用(感谢 Eclipse)后,我最终进入了 org.hibernate.cfg.Environment 类(版本 4.2.0.CR2 的代码),在那里我找到了以下代码(我的版本和 4.2 中的代码都是相同的.0CR2):

 public static BytecodeProvider buildBytecodeProvider(Properties properties) {
    String provider = ConfigurationHelper.getString( BYTECODE_PROVIDER, properties, "javassist" );
    LOG.bytecodeProvider( provider );
    return buildBytecodeProvider( provider );
}

private static BytecodeProvider buildBytecodeProvider(String providerName) {
    if ( "javassist".equals( providerName ) ) {
        return new org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl();
    }

    LOG.unknownBytecodeProvider( providerName );
    return new org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl();
}

到目前为止,我可以说它是您的代理工厂的 Javassist 实现,并且不会有标准的方法来更改它。


疯子旁注

我要说的是纯粹的疯狂,它不应该被考虑到生产代码中,但只有在它真正工作/学术/让事情发生的情况下才会考虑。

<锤子黑客>

  • 您可以尝试扩展自己的框架来检测类,以便不仅添加满足您需求的字节码,还添加休眠需要的字节码 - 我会说这就像将您的操作与org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl操作合并。
  • 然后,您可以重命名扩展类以BytecodeProviderImpl将其放在同一个包中org.hibernate.bytecode.internal.javassist,最后将其放在类路径中的某个位置,类加载器会在 jar 中的那个之前找到它(或者可能使用自定义类加载器)

然后你会喜欢Hibernate、你的框架和可能整个 JVM 惊慌失措的尖叫,不知道该做什么,或者它可以工作......

</锤子黑客>

无论如何,如果您有时间并愿意尝试,请告诉我是否成功。


更新

在评论部分聊了一会儿之后,我有了使用自定义EntityPersister的想法。因为我对此不太确定,所以我用谷歌搜索了一下,看看我是否能找到一些可以告诉我我的想法是否可行的东西。

甚至比找出我的直觉是否正确更好,我在 Stackoverflow 中发现了一个与您的问题非常相似的问题。可悲的是,那里没有公认的答案。

但是该问题的第一个答案给出了与我的想法类似的链接。引用 Pascal Thivent 的话:

自定义 EntityPersister 实现(您可以在 Hibernate 初始化期间使用自定义 Configuration 为特定实体注册

确实,该示例适用于 Grails 中的 Hibernate,但在纯 Java 中几乎相同:

 public void registerCustomEntityPersister(Configuration configuration) {
     final Iterator<PersistentClass> classesIterator = configuration.getClassMappings();
 while (classesIterator.hasNext()) {
    final PersistentClass persistentClass = classesIterator.next();
        if (checkIfIsOneTheClassesThatMatters(persistentClass)) {
          persistentClass.etEntityPersisterClass(CustomEntityPersister.class); 
        }
 }

尽管这看起来可行,但看起来工作量太大了,因为实现 EntityPersister 看起来并不那么简单……太多的事情。您可以尝试扩展 Hibernate 使用的默认一个(我真的不知道是哪一个)并尝试覆盖 getProxy() 方法以返回您的检测类之一。

抱歉,如果它仍然不是答案,但遗憾的是我不是 Hibernate 专家,我通常开箱即用,实际上由于 javassist 标签,我发现了你的问题,发现它很有趣。

我希望至少我给了你可以帮助你的信息。

于 2013-03-26T09:27:23.853 回答