【问题标题】:Can I use Spring Data JPA Auditing without the orm.xml file (using JavaConfig instead)?我可以在没有 orm.xml 文件的情况下使用 Spring Data JPA 审计(改用 JavaConfig)吗?
【发布时间】:2014-04-17 05:42:11
【问题描述】:

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

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

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

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

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

    <!--  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 类中设置了一个断点,但它从未被击中。

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

【问题讨论】:

  • 如何将 XML 配置连接到 JavavConfig?您是否有机会在 GitHub 存储库等中分享该项目?我可以成功地将auditing sample project 更改为在AbstractEntity 上使用@EntityListeners 并从项目中删除orm.xml。您介意检查一下示例项目和您的项目之间的差异吗?
  • @OliverGierke 我的 XML 是我的 applicationContext 文件的一部分,该文件由 web.xml 中定义的 Spring Listener 加载。如果可以在较小的级别上重现问题,我将尝试整理一个示例项目并推送到 github。
  • @OliverGierke 我花了一大早上的时间试图在示例应用程序中重现问题。最终我能够重现该问题,但我认为我将其缩小为 jRebel 问题。我还不能 100% 确定这一点,但这似乎就是它的发展方向。我会及时通知你。
  • @OliverGierke 原来这是一个 jRebel 问题。我一直在使用 aspectJ 在 @EntityListeners() 中编译时间编织,但是当 jRebel 加载类时,它使用指向原始实体而不是增强类的类路径。我不得不删除 jRebel maven 插件生成的 rebel.xml 文件,现在一切似乎都正常工作了。
  • 嘿@EricB。我们正在使用Jrebel 并面临同样的问题。让jrebelSpring Data Auditing 一起玩的任何想法

标签: java spring jpa spring-data audit


【解决方案1】:

短版:否

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

JPA 2.0:

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

长版:解决方法...

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

JPA 2.0:

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

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

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

JPA 2.0:

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


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

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 类,但我没有尝试...


参考:JSR-000317 Java Persistence 2.0 - Final Release

【讨论】:

  • 第二次尝试...当我创建自己的审核课程时效果很好...我会在答案中发布。
  • 没有 xml 解决方法不起作用。 @JustinSmith 你的解决方案就像一个魅力..但不知道为什么
【解决方案2】:

使用斯蒂芬的答案,https://stackoverflow.com/a/26240077/715640

我使用自定义侦听器完成了这项工作。

@Configurable
public class TimestampedEntityAuditListener {

    @PrePersist
    public void touchForCreate(AbstractTimestampedEntity target) {
        Date now = new Date();
        target.setCreated(now);
        target.setUpdated(now);
    }

    @PreUpdate
    public void touchForUpdate(AbstractTimestampedEntity target) {
        target.setUpdated(new Date());
    }
}

然后在我的基类中引用它:

@MappedSuperclass
@EntityListeners({TimestampedEntityAuditListener.class})
public abstract class AbstractTimestampedEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    @Temporal(TemporalType.TIMESTAMP)
    private Date updated;

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

FWIW,我在 spring-boot 项目中使用它,没有 orm.xml 文件。

【讨论】:

  • 您能否明确说明您帖子中的 @CreatedDate@LastModifiedDate 注释?
  • @Stephan 我不确定你的意思。再看一遍,这种方法甚至可能不需要这些注释,因为自定义审计类根本不使用注释,只是抽象类。
  • 如果这些注释甚至可能不需要,为什么它们在代码中?
  • 已更新,感谢您帮助我走上正轨。
【解决方案3】:

在 Spring Data 1.9 中,您可以使用几个注释启用 JPA 审计。

来自文档 - http://docs.spring.io/spring-data/jpa/docs/1.9.4.RELEASE/reference/html/#jpa.auditing

使用@EntityListeners(AuditingEntityListener.class) 注解启用逐类审计。我在基类中使用它。

您还需要在 @Configuration 类上使用 @EnableJpaAuditing 才能启用一般审计。

【讨论】:

    猜你喜欢
    • 2017-10-09
    • 2020-09-26
    • 2018-07-12
    • 2014-08-21
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多