我可以在没有 orm.xml 文件的情况下使用 Spring Data JPA 审计(改用 JavaConfig)吗?

2022-01-18 00:00:00 spring java jpa spring-data audit

我正在尝试让 Spring Data Auditing 在我的 Spring 3.2.8/Spring Data 1.5/Hibernate 4 项目中工作.

I'm trying to get Spring Data Auditing to work in my Spring 3.2.8 / Spring Data 1.5 / Hibernate 4 project.

根据 Spring Data Auditing docs,我已将 @CreatedBy 等注释添加到我的实体中,由 AuditorAware 实现创建,并在我的 JavaConfig 中对其进行实例化.但是,它似乎永远不会触发.

As per the Spring Data Auditing docs, I've added the @CreatedBy, etc annotations to my entities, created by AuditorAware implementation, and instantiated it from within my JavaConfig. However, it never seems to fire.

我发现文档有点混乱.看来JavaConfig条目替换了xml条目,但我不确定.

I find the docs a little confusing. It appears that the JavaConfig entry replaces the xml entry, but I am not sure.

我的应用程序中目前没有任何 orm.xml 文件.老实说,我什至不确定在哪里/如何配置它,或者我为什么需要它.我所有的实体都在使用注释.我曾尝试将 @EntityListeners(AuditingEntityListener.class) 添加到实体中,但这没有帮助.

I don't currently have any orm.xml file in my application. To be entirely honest, I'm not even sure where/how to configure it, or why I need it. All my entities are using annotations. I have tried adding @EntityListeners(AuditingEntityListener.class) to the entity, but that has not helped.

我当前的实体管理器是在没有 persistence.xml 文件的情况下定义的:

My current entity manager is defined without a persistence.xml file:

    <!--  entity manager -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
        <property name="packagesToScan" value="com.ia.domain"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.query.substitutions">true '1', false '0'</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                <prop key="hibernate.connection.charSet">UTF-8</prop>
            </props>
        </property>
    </bean>

Java配置:

@Configuration
@EnableJpaAuditing
public class AuditConfig {
    @Bean
    public AuditorAware<User> auditorProvider(){
        return new SpringSecurityAuditorAware();
    }
}

实体:

@EntityListeners({AuditingEntityListener.class})
@Entity
public class User
{

  @TableGenerator(name="UUIDGenerator", pkColumnValue="user_id", table="uuid_generator", allocationSize=1)
  @Id
  @GeneratedValue(strategy=GenerationType.TABLE, generator="UUIDGenerator")
  @Column(name="id")
  private Long id;

  @NotNull
  private String username;

  @CreatedDate
  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name="created_date", nullable=false)
  private Date createdDate;

  @LastModifiedDate
  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name="last_modified_date", nullable=false)
  private Date lastModifiedDate;

  @CreatedBy
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="created_by")
  private User createdBy;

  @LastModifiedBy
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="last_modified_by")
  private User lastModifiedBy;
  private String password;
  private Boolean enabled;


...
}

我在 SpringSecurityAuditorAware 类中设置了一个断点,但它从未被击中.

I've put a breakpoint in my SpringSecurityAuditorAware class but it is never being hit.

我还需要 orm.xml 文件吗?EntityManager 是如何/在哪里引用它的?

Do I still need an orm.xml file? How/where is this referenced from the EntityManager?

推荐答案

短版:无

从 JPA 2.0 开始,无法在没有 XML 文件 (orm.xml) 的情况下定义此类实体侦听器.

Short version: No

As of JPA 2.0, it is not possible to define such entity listener without an XML file (orm.xml).

默认实体侦听器——适用于持久单元中所有实体的实体侦听器——可以通过 XML 描述符指定.(第 93 页)

Default entity listeners—entity listeners that apply to all entities in the persistence unit—can be specified by means of the XML descriptor. (p.93)

长版:解决方法...

如果您项目中的所有实体都扩展了 AbstractAuditable 超类,那么您可以将 @EntityListeners({AuditingEntityListener.class}) 放在 AbstractAuditable 上.附加到实体类的侦听器由其子类继承.

Long version: The workaround...

If all entities in your project extends an AbstractAuditable superclass then you can put @EntityListeners({AuditingEntityListener.class}) on AbstractAuditable. Listeners attached to an entity class are inherited by its subclasses.

继承层次结构中的多个实体类和映射的超类可以定义侦听器类和/或直接在类上的生命周期回调方法.(第 93 页)

Multiple entity classes and mapped superclasses in an inheritance hierarchy may define listener classes and/or lifecycle callback methods directly on the class. (p.93)

请注意,子类可以使用 @ExcludeSuperclassListeners 注释显式排除继承的侦听器.

Note that a subclass can exclude explicitly an inherited listener using the @ExcludeSuperclassListeners annotation.

我想引用规范中最后一个有趣的脚注:

There is one last interesting footnote from the spec I'd like to quote:

排除的侦听器可以通过列出来重新引入实体类它们在 EntityListeners 注释或 XML 中显式实体侦听器元素.(脚注 [45] 第 97 页)

Excluded listeners may be reintroduced on an entity class by listing them explicitly in the EntityListeners annotation or XML entity-listeners element. (Footnote [45] p.97)

<小时>

以下是一些用于说明解决方法的代码:


Here is some code for illustrating the workaround:

AbstractAuditableEntity.java

import java.util.Date;

import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@MappedSuperclass
@EntityListeners({AuditingEntityListener.class}) // AuditingEntityListener will also audit any subclasses of AbstractAuditable...
public abstract class AbstractAuditableEntity {
    @Id
    @GeneratedValue
    private Long id;

    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
}

MyEntity.java

@Entity
public abstract class MyEntity extends AbstractAuditableEntity {

}

我认为可以使用接口 Auditable (@EntityListeners 可以出现在接口上)而不是 AbstractAuditable 类,但我没有试试看……

I think an interface Auditable may be used (@EntityListeners can appear on an interface) instead of an AbstractAuditable class but I didn't try...

参考:JSR-000317 Java Persistence 2.0 - 最终版本

相关文章