JPA Lifecycle Events And Callback Methods

JPA Lifecycle Events And Callback Methods

JPA Lifecycle Events And Callback Methods

每周至少一篇技术文档,这是这一周的。这篇文章涉及两篇文档。比较简单。 JPA Lifecycle Events&Entity listeners and Callback methods,两篇文档,推荐第一篇,以第一篇为主,先基本翻译第一篇。

JPA Lifecycle Events JPA 生命周期事件

Callback methods are user defined methods that are attached to entity lifecycle events and are invoked automatically by JPA when these events occur.

回调方法是用户定义的方法,这些回调方法跟entity的生命周期相关联,并且当生命周期的事件发生时被JPA自动调用。

This page covers the following topics: 这篇文章涉及到一些话题。

  • Internal Callback Methods 内部回调方法
  • Implementation Restrictions 约束实现
  • Listeners and External Callback Methods 监听器Entity Listeners和外部回调方法
  • Default Entity Listeners 默认的 Entity Listeners
  • Callback Invocation Order 回调方法调用顺序

Internal Callback Methods 内部回调方法

内部回调方法是指,方法在Entity类中定义的回调方法。比如,下边的实体类定义了所有支持的回调方法,用的是空的实现。

@Entity
public static class MyEntityWithCallbacks {  
    @PrePersist void onPrePersist() {}
    @PostPersist void onPostPersist() {}
    @PostLoad void onPostLoad() {}
    @PreUpdate void onPreUpdate() {}
    @PostUpdate void onPostUpdate() {}
    @PreRemove void onPreRemove() {}
    @PostRemove void onPostRemove() {}
}


内部调用方法应该是返回值为空的并且没有任何参数的的方法。它们可以任意命名,任意的访问级别(public,protected,package and private),但是不能够是静态方法。

这些注解指定了什么时候这个回调方法会被调用:

  • @PrePersist - before a new entity is persisted (added to the EntityManager). 实体被持久化之前。
  • @PostPersist - after storing a new entity in the database (during commit or flush). 保存一个新实体到数据库之后。
  • @PostLoad - after an entity has been retrieved from the database. 实体被重新从数据库获取之后,游离态变为持久态之后。
  • @PreUpdate - when an entity is identified as modified by the EntityManager.当一个实体被EntityManager识别为有修改时。
  • @PostUpdate - after updating an entity in the database (during commit or flush).当一个实体被更新到数据库之后。
  • @PreRemove - when an entity is marked for removal in the EntityManager. 当一个实体被EntityManager标记为可删除时。即将被从数据库删除时。
  • @PostRemove - after deleting an entity from the database (during commit or flush). 在数据库删除一个实体之后。

一个实体类可能包括任何生命周期事件的子集或组合的回调方法。但是可以对同一个事件有不止一个回调方法。然而,相同的方法可能会被用来响应多种事件通过在一个回调方法上加多个注解。

默认情况下,一个父类的回调方法也会被子类实体对象调用,除非这个回调方法被子类覆盖。

Implementation Restrictions 实现中的约束限制

为避免跟原始数据库操作冲突,原始数据库操作触发生命周期事件(触发的时候数据库操作还在进行中,没有结束),所以回调方法不应该调用EntityMan­ager or Query 的方法,并且不应该访问任何其他的实体对象。

如果一个回调方法在一个活跃状态下的事务中抛出一个异常,这个事务会被标记为回滚并且这次操作中不会有其他的回调方法再被调用。

Listeners and External Callback Methods 监听器和外部回调方法

外部回调方法是被定义在实体类之外的在特殊的监听器类中:

public class MyListener {  
    @PrePersist void onPrePersist(Object o) {}
    @PostPersist void onPostPersist(Object o) {}
    @PostLoad void onPostLoad(Object o) {}
    @PreUpdate void onPreUpdate(Object o) {}
    @PostUpdate void onPostUpdate(Object o) {}
    @PreRemove void onPreRemove(Object o) {}
    @PostRemove void onPostRemove(Object o) {}
}

外部的回调方法(监听器类中)应该是返回值为空并且有一个指定实体的参数,这个实体是生命周期事件的源。这个参数可以是任何配置实际值的类型。(比如,在上面的代码中,Object可以被替换为一个更具体的类型)。这个监听器类应该是没有状态的,并且有一个public的无参构造函数(或者是没有构造函数)来开启自动实例化。

监听类被关联到实体类是通过使用@EntityListeners注解:

@Entity @EntityListeners(MyListener.class)
public class MyEntityWithListener {  
}

多个监听器类也可以被关联到一个实体类上:

@Entity
javax.persistence.Entity  
JPA annotation  
Specifies that the class is an entity.  
See JavaDoc Reference Page...  
 @EntityListeners({MyListener1.class, MyListener2.class})
public class MyEntityWithTwoListeners {  
}

被关联在一个实体类的监听器是会被这个实体类的子类继承的,除非子类显式剔除继承使用@ExcludeSuperclassListeners注解:

@Entity @ExcludeSuperclassListeners
public class EntityWithNoListener extends EntityWithListener {  
}

Default Entity Listeners 默认的实体监听器

默认的实体监听器是一种应该被默认应用到所有实体类上的监听器。目前,(不清楚作者写文档时的JPA版本),默认的监听器只能通过被指定在XML配置文件中,因为没有如此功能的注解:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"  
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
 http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
  <persistence-unit-metadata>
    <persistence-unit-defaults>
      <entity-listeners>
        <entity-listener class="samples.MyDefaultListener1" />
        <entity-listener class="samples.MyDefaultListener2" />
      </entity-listeners>
    </persistence-unit-defaults>
  </persistence-unit-metadata>
</entity-mappings>  

这个映射文件必须是放在默认的位置META-INF/orm.xml,或者其他位置,在in the persistence unit definition持久化单元中显式指定的(在persistence.xml中指定的)。

默认的监听器被默认应用到所有的实体类上。@ExcludeDefaultListeners注解会被使用来exclude剔除一个实体类和它所有子孙类的默认监听器:

@Entity @ExcludeDefaultListeners
public class NoDefaultListenersForThisEntity {  
}

@Entity
public class NoDefaultListenersForThisEntityEither  
  extends NoDefaultListenersForThisEntity {
}

Callback Invocation Order 回调方法调用顺序

如果不止一个回调方法要被调用对于一个生命周期事件,(比如,多个监听器),调用顺序会基于如下规则:

  • 所有的外部回调方法(监听器类里边的方法)在内部回调方法之前被调用。
  • 默认的监听器首先调用,然后监听器按继承关系从高到低调用,直到实体自己。如果不止一个默认监听器或者不止一个监听器在同一个类上(自己,父类,父父类...),调用顺序按照定义的顺序。
  • 内部回调方法被调用也是从高到低调用,直到自己。

补充

第二篇文章提到的,内部回调方法,一种事件(一种注解),最多出现一次。


Related Article