Hibernate @PostLoad 永远不会被调用

Posted

技术标签:

【中文标题】Hibernate @PostLoad 永远不会被调用【英文标题】:Hibernate @PostLoad never gets invoked 【发布时间】:2010-05-10 12:47:47 【问题描述】:

查看了许多论坛,但没有找到答案...简单的东西,用@PostLoad 注释的方法永远不会被调用...通过@EntityListeners 添加了侦听器,但问题仍然存在。我正在使用基于 SessionFactory 的配置。

【问题讨论】:

【参考方案1】:

当使用基于 SessionFactory 的配置时,EJB3 @PostLoad 注释不起作用,后加载方法将永远不会被调用。

使用 Hibernate 的 Interceptors or events 或基于 EntityManager 的配置。

【讨论】:

使用 SessionFactory 时回调绝对可以工作。您只需自己启用适当的 Hibernate 事件侦听器。 以下是启用事件监听器的方法:n1njahacks.wordpress.com/2016/10/07/…【参考方案2】:

在使用 SessionFactory 时,还有一种替代 hibernate 的拦截器或事件方法的方法:实现 Lifecycle 接口。

【讨论】:

但要注意这个错误:hibernate.onjira.com/browse/HHH-6043 也适用于 Lifecycle.onLoad(在初始化集合之前调用 - 直到它在 Hibernate 4.1.8 中修复)【参考方案3】:

这是在 Hibernate 5 中启用 JPA 的 post op annotations 的方法。

Hibernate 的IntegratorServiceImpl 使用java.util.ServiceLoader API,因此我们可以指定一个额外的org.hibernate.integrator.spi.Integrator 实现列表,我们希望SessionFactory 使用。

我们需要做的就是在META-INF/services/org.hibernate.integrator.spi.Integrator中指定一个服务提供商:

# This allows us to use JPA-style annotation on entities, such as @PostLoad
our.custom.JpaAnnotationsIntegrator

您还需要确保相应版本的“hibernate-entitymanager”jar 在您的类路径中。

our.custom.JpaAnnotationsIntegrator(取自org.hibernate.jpa.event.spi.JpaIntegrator):

package our.custom;

import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.internal.MetadataImpl;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.jpa.event.internal.core.JpaPostDeleteEventListener;
import org.hibernate.jpa.event.internal.core.JpaPostInsertEventListener;
import org.hibernate.jpa.event.internal.core.JpaPostLoadEventListener;
import org.hibernate.jpa.event.internal.core.JpaPostUpdateEventListener;
import org.hibernate.jpa.event.internal.jpa.CallbackBuilderLegacyImpl;
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl;
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
import org.hibernate.jpa.event.spi.jpa.ListenerFactoryBuilder;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

/**
 * This integrator allows us to use JPA-style post op annotations on Hibernate entities.
 *

 * This integrator is loaded by <code>org.hibernate.integrator.internal.IntegratorServiceImpl</code> from
 * <code>META-INF/services/org.hibernate.integrator.spi.Integrator</code> file.
 *

 * <b>Note</b>: This code is lifted directly from <code>org.hibernate.jpa.event.spi.JpaIntegrator</code>
 *
 * @author Val Blant
 */
public class JpaAnnotationsIntegrator implements Integrator 
    private ListenerFactory jpaListenerFactory;
    private CallbackBuilder callbackBuilder;
    private CallbackRegistryImpl callbackRegistry;

    @Override
    public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) 
        final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );

        this.callbackRegistry = new CallbackRegistryImpl();

        // post op listeners
        eventListenerRegistry.prependListeners( EventType.POST_DELETE, new JpaPostDeleteEventListener(callbackRegistry) );
        eventListenerRegistry.prependListeners( EventType.POST_INSERT, new JpaPostInsertEventListener(callbackRegistry) );
        eventListenerRegistry.prependListeners( EventType.POST_LOAD, new JpaPostLoadEventListener(callbackRegistry) );
        eventListenerRegistry.prependListeners( EventType.POST_UPDATE, new JpaPostUpdateEventListener(callbackRegistry) );

        // handle JPA "entity listener classes"...
        final ReflectionManager reflectionManager = ( (MetadataImpl) metadata )
                .getMetadataBuildingOptions()
                .getReflectionManager();

        this.jpaListenerFactory = ListenerFactoryBuilder.buildListenerFactory( sessionFactory.getSessionFactoryOptions() );
        this.callbackBuilder = new CallbackBuilderLegacyImpl( jpaListenerFactory, reflectionManager );
        for ( PersistentClass persistentClass : metadata.getEntityBindings() ) 
            if ( persistentClass.getClassName() == null ) 
                // we can have non java class persisted by hibernate
                continue;
            
            callbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry );
        
    

    @Override
    public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) 
        if ( callbackRegistry != null ) 
            callbackRegistry.release();
        
        if ( callbackBuilder != null ) 
            callbackBuilder.release();
        
        if ( jpaListenerFactory != null ) 
            jpaListenerFactory.release();
        
    
 

【讨论】:

【参考方案4】:

我也一直在努力使用会话工厂在 Hibernate4 上完成这项工作。

我发现解决方案非常简单,但在任何地方都没有使用 Integrator 记录(显然是 Hibernate4 处理 SessionFactory 和侦听器的方式)。 hibernate-entitymanager 项目提供了一个集成器来添加所需的侦听器以将 EJB3 的注释 @PostLoad, ... 链接到会话工厂。只需以 SPI 方式声明类 JpaIntegrator

具体来说,只需在META-INF/services文件夹中添加一个名为org.hibernate.integrator.spi.Integrator的文件,并在其中声明实现类(org.hibernate.ejb.event.JpaIntegrator)

【讨论】:

不错的解决方案。仅供参考,从 Hibernate 4.3.5 开始,文件的内容应该是“org.hibernate.jpa.event.spi.JpaIntegrator”。 这也是我采用的解决方案,尽管我发现它会破坏 Hibernate 5 中的刷新级联。请参阅下面的答案以获得修复。 @Matt 我知道这是一个非常古老的问题,但我应该在哪里找到这个 META-INF/Services ?我只能在我下载hibernate的文件夹中找到它,并且在进行更改后仍然无法正常工作。【参考方案5】:

或者启用处理 JPA 回调的 Hibernate 事件侦听器。这正是 HEM 所做的。 Hibernate 3 和 Hibernate 4 的实现方式不同(您从未提及您使用的是哪个版本);查看文档以获取有关 (a) 所涉及的事件侦听器和 (b) 如何指定自定义侦听器集的详细信息。

【讨论】:

也许我很厚,但我很难在 Hibernate 4 的文档中找到如何做到这一点。

以上是关于Hibernate @PostLoad 永远不会被调用的主要内容,如果未能解决你的问题,请参考以下文章

QAbstractItemModel data() 永远不会被调用

S3.putObject - 回调永远不会被调用

Android onSystemUiVisibilityChange 永远不会被调用

SSE:“onmessage”永远不会被调用

意图服务永远不会被调用

是否可以仅按需动态触发@PostLoad 方法的调用