单独指定 JPA 实体侦听器,独立于其关联实体

Posted

技术标签:

【中文标题】单独指定 JPA 实体侦听器,独立于其关联实体【英文标题】:Specifying JPA entity listeners separately being independent of its associated entity 【发布时间】:2015-12-15 15:00:48 【问题描述】:

实体侦听器通常放置在相应的实体类上,例如,

@Entity
@EntityListeners(EntityListener.class)
public class Entity implements Serializable 

    //...

应用程序可以使用一个或多个类库在不同的项目/模块之间共享通用功能。除了 EE 模块之外,类库基本上还要求实体作为依赖项存在于编译时类路径中,即实体存在于企业应用程序中的类库和 EE 模块这两个地方。因此,给定示例中的类 EntityListener 需要存在于类库的编译时类路径中(它不能只添加到 EE 模块中)。

如果实体侦听器不与各个实体紧密耦合并单独指定,则无需将此依赖项(侦听器)添加到类库中,即实体侦听器将仅存在于 EE 项目中其中 EJB 完全可以使用 @Inject 进行注入。

是否有可能将此注释@EntityListeners(EntityListener.class)与其关联实体分开,以便可以在单独的位置单独声明?不需要将此注释与其各自的实体紧密耦合。

使用具有 EclipseLink 2.6.0 (JPA 2.1) 的 GlassFish 4.1。


这是必需的,因为有一个 problem 使用 CDI 特定工件 @Inject 将 EJB 注入到此类实体侦听器中在类库中可用。如果侦听器仅存在于 EE 项目(模块)中(而不存在于类库中),则可以通过使用 @Inject 将 EJB 注入到侦听器中。

【问题讨论】:

【参考方案1】:

将注释@EntityListeners 从实体中取出的一种方法是同时使用XML 和注释方法。混合和匹配 XML 描述符和元数据注释是完全有效和记录的。

为了覆盖该注释,必须在名为 orm.xml[1] 的文件中注册实体侦听器,如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1"
                 xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm orm_2_1.xsd">

    <entity class="com.example.entity.Entity">
        <entity-listeners>
            <entity-listener class="com.example.entity.listeners.EntityListener"/>
        </entity-listeners>
    </entity>

    <!--Other listeners-->

</entity-mappings>

相应的监听器类可以保持不变,注释如下。

public class EntityListener 

    @PostPersist
    @PostUpdate
    @PostRemove
    public void onChange(Entity entity) 

        // Do something with the entity.
    

这些回调可能会因功能要求而异。


如有必要,还可以将回调定义为 XML 元素,避免在侦听器类中添加回调注释,例如,

<entity class="com.example.entity.Entity">
    <entity-listeners>
        <entity-listener class="com.example.entity.listeners.EntityListener">
            <post-persist method-name="onChange"/>
            <post-update method-name="onChange"/>
            <post-remove method-name="onChange"/>
        </entity-listener>
    </entity-listeners>
</entity>

现在不需要监听器类中的这三个注解,即@PostPersist@PostUpdate@PostRemove,因为它们已在 XML 描述符中注册。


[1] 像 NetBeans 这样的 IDE 似乎没有生成 orm.xml 文件的向导支持。在 NetBeans 项目中,需要在 src/conf(或任何其他自定义配置位置)下手动创建一个 XML 文件,以便应用程序构建者可以在构建/部署应用程序时将该文件放在 META-INF/orm.xml 下。

【讨论】:

【参考方案2】:

是的,您可以使用 xml 定义 default entity listener。

【讨论】:

接收当前持久化单元中所有实体的所有事件的默认监听器要做什么? 听说过if statement? :) 还是地图(实体实例类型 -> 您的自定义侦听器实现)?毕竟,这或多或少是 JPA 提供者注册和查找侦听器的方式;他们提供了直接在实体上定义它的快捷方式,这只是一种方便。 我接受了我自己的答案,因为它实际上对我有用。

以上是关于单独指定 JPA 实体侦听器,独立于其关联实体的主要内容,如果未能解决你的问题,请参考以下文章

在 JPA 中,我如何找到具有属性值的所有类型和具有属性值的 ManyTomany 相关实体?

实体持久注册验证侦听器

如何创建扩展 AuditingEntityListener 的自定义审计实体侦听器

有没有办法在测试中选择性地禁用对实体修改的审计?

使用合并持久性单元管理器后未调用休眠事件侦听器

JPA实体监听器-@EntityListeners