使用 Spring Boot 和 Spring Data JPA 的 Hibernate 拦截器或侦听器

Posted

技术标签:

【中文标题】使用 Spring Boot 和 Spring Data JPA 的 Hibernate 拦截器或侦听器【英文标题】:Hibernate interceptor or listener with Spring Boot and Spring Data JPA 【发布时间】:2017-02-01 11:38:40 【问题描述】:

我想在保存对象的一组子对象之前运行一些检查(级联 = 全部)。

我正在使用 Spring Boot 和 Spring Data JPA,并且想知道哪种方法最好:Hibernate 侦听器或拦截器。每个的优点/缺点是什么?您是否碰巧有一个您认为最好的方法的示例?

我在 XML 中配置之前使用过 Hibernate 侦听器,如下所示:

    <property name="eventListeners">
        <map>
            <entry key="post-update">
                <list>
                    <ref bean="myListener" />
                </list>
            </entry>
        </map>
    </property>

关于会话工厂(旧项目)。但是现在我的大部分配置都在注释中(因为 Spring Boot),我想让配置尽可能简单和轻便,所以也许拦截器会是一个更好的解决方案。

谢谢。

【问题讨论】:

【参考方案1】:

我为自己做了很多环顾四周,并认为我会分享我的工作(我在底部添加了有用的(非内联)链接)。

拦截器

要使用拦截器,您可以扩展org.hibernate.EmptyInterceptor 类并覆盖您要拦截的方法。 您可能需要onSave(...)

package foo.bar;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import java.io.Serializable;

public class MyInterceptor extends EmptyInterceptor 
    @Override
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) 
        // do your checks here
        return false;
    

您必须使用 Spring/Hibernate register your interceptor。 您可以在application.properties or application.yml 中执行此操作。

spring:
  jpa:
    properties:
      hibernate.ejb.interceptor: foo.bar.MyInterceptor

拦截器的好处是它(可能)更少的代码和相对简单的配置。 缺点是您的整个应用程序只能使用一个,并且使用该 API 可能会令人困惑。

事件监听器

对于事件,您实现 Hibernate 的 org.hibernate.event.spi.*Listener 接口之一。 您可能需要 org.hibernate.event.spi.PreInsertEventListener 在您的情况下。

您必须在EventListenerRegistry 中注册您的活动。 为此,您可以将您的类设为@Component@AutowireEntityManagerFactory,并创建一个@PostConstruct 方法来注册您的类。

package foo.bar;

import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.internal.SessionFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;

@Component
public class MyEventListener implements PreInsertEventListener 
    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @PostConstruct
    private void init() 
        SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
        EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
        registry.getEventListenerGroup(EventType.PRE_INSERT).appendListener(this);
    

    @Override
    public boolean onPreInsert(PreInsertEvent preInsertEvent) 
        // do your checks here
        return false;
    

侦听器的好处是您可以拥有任意数量的侦听器,API 比拦截器更好,并且代码和配置都在一个地方。 缺点是配置更长,涉及更多。


https://docs.jboss.org/hibernate/orm/3.5/reference/en-US/html/events.html How to use Spring managed Hibernate interceptors in Spring Boot? https://dzone.com/articles/spring-managed-hibernate-event-listeners

【讨论】:

Hibernate 支持会话范围的拦截器以及应用范围的拦截器,您需要使用此属性而不是“hibernate.ejb.interceptor.session_scoped” 太棒了,我看了很多,得到了和你一样好的指导。 精彩的解释兄弟!【参考方案2】:

你好

首先您可以查看:https://www.baeldung.com/database-auditing-jpa,其中详细解释了每个选项。

我个人会推荐Hibernate Interceptor,易于使用和理解。根据项目的复杂程度,在大多数情况下都可以。

为了在您的应用程序中配置它,您只需添加:spring.jpa.properties.hibernate.ejb.interceptor = path.to.interceptor(在 application.properties 中)。拦截器本身应该是@Component

只要拦截器实际上不使用任何 bean。否则会有点复杂,但我很乐意提供解决方案。

不要忘记添加 application-test.properties,一个 EmptyInterceptor 在测试中不使用日志系统(或任何你想使用它的东西)(这不会很有帮助)。

希望这对你有用。

最后一点:始终更新您的 Spring / Hibernate 版本(尽可能使用最新版本),您会发现大多数代码将变得多余,因为新版本会尽可能减少配置可能。

【讨论】:

以上是关于使用 Spring Boot 和 Spring Data JPA 的 Hibernate 拦截器或侦听器的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2Spring Boot CLI

Spring boot启动后没有生成日志文件问题排错

spring boot-18.使用dubbo发布分布式服务

spring-boot实战12:Spring Boot中使用JavaMailSender发送邮件

Spring Boot Servlet 过滤 监听

Spring Boot 有哪些优点?