如何创建扩展 AuditingEntityListener 的自定义审计实体侦听器
How to create custom auditing entity listener that extends AuditingEntityListener
我已经通过 Sping Data JPA 实现了审计,但现在我希望能够控制更新并使用自定义逻辑创建时间戳。所以我想编写一个扩展 Auditingentitylistener 的自定义审计实体侦听器。
我有以下通用实体 class,我在其中注册了自定义审计实体侦听器:
@MappedSuperclass
@Audited
@EntityListeners(CustomAuditingEntityListener.class)
public class AuditableEntity extends BaseEntity {
@CreatedDate
@Column(name = "created", nullable = false)
private Date created;
@CreatedBy
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "created_by_id", foreignKey = @ForeignKey(name = "fk_entity_created_by_id"))
private Account createdBy;
@LastModifiedDate
@Column(name = "last_updated", nullable = false)
private Date lastUpdated;
@LastModifiedBy
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "last_updated_by_id", foreignKey = @ForeignKey(name = "fk_entity_last_updated_by_id"))
private Account lastUpdatedBy;
protected AuditableEntity() {
}
...
}
CustomAuditingEntityListener class 定义为
@Configurable
public class CustomAuditingEntityListener extends AuditingEntityListener {
public CustomAuditingEntityListener() {
super();
}
@Override
@PrePersist
public void touchForCreate(Object target) {
if (//custom logic) {
super.touchForCreate(target);
}
}
@Override
@PreUpdate
public void touchForUpdate(Object target) {
if (//custom logic) {
super.touchForUpdate(target);
}
}
}
自定义审计实体侦听器被正确调用,但是当 super.touchForCreate(target)
或 super.touchForUpdate(target)
被调用时,时间戳未设置,因为 AuditingEntityListener class 中的处理程序为空。
这是 AuditingEntityListener 的代码 class:
package org.springframework.data.jpa.domain.support;
@Configurable
public class AuditingEntityListener implements ConfigurableObject {
private ObjectFactory<AuditingHandler> handler;
public AuditingEntityListener() {
JoinPoint var2 = Factory.makeJP(ajc$tjp_1, this, this);
JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);
if (this != null && this.getClass().isAnnotationPresent(Configurable.class) && AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class))) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$before$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$e854fa65(this);
}
if ((this == null || !this.getClass().isAnnotationPresent(Configurable.class) || !AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class))) && this != null && this.getClass().isAnnotationPresent(Configurable.class) && AbstractDependencyInjectionAspect.ajc$iff1(var1)) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspectea6722c(this);
}
if (!AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class)) && AbstractDependencyInjectionAspect.ajc$iff1(var2)) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspectea6722c(this);
}
}
public void setAuditingHandler(ObjectFactory<AuditingHandler> auditingHandler) {
Assert.notNull(auditingHandler, "AuditingHandler must not be null!");
this.handler = auditingHandler;
}
@PrePersist
public void touchForCreate(Object target) {
if (this.handler != null) {
((AuditingHandler)this.handler.getObject()).markCreated(target);
}
}
@PreUpdate
public void touchForUpdate(Object target) {
if (this.handler != null) {
((AuditingHandler)this.handler.getObject()).markModified(target);
}
}
static {
ajc$preClinit();
}
}
有人可以解释我如何确保 AuditingHandler 不为 null 并且设置为默认 AuditingEntityListener class 吗?
在 Spring 5.1 中,有一种相当直接的方法可以在自定义实体侦听器中自动装配 Spring 组件,因此可以使用 AuditingHandler
。
1. 将客户实体侦听器声明为 Spring 组件。使用构造函数注入。
@Component
public class CustomAuditingEntityListener {
private ObjectFactory<AuditingHandler> handler;
public CustomAuditingEntityListener(ObjectFactory<AuditingHandler> auditingHandler) {
this.handler = auditingHandler;
}
@Override
@PrePersist
public void touchForCreate(Object target) {
if (//custom logic) {
AuditingHandler object = handler.getObject();
if (object != null) {
object.markCreated(target);
}
}
}
@Override
@PreUpdate
public void touchForUpdate(Object target) {
if (//custom logic) {
AuditingHandler object = handler.getObject();
if (object != null) {
object.markModified(target);
}
}
}
}
2. 通过设置适当的配置告诉 Hibernate 使用 Spring 作为 bean 提供者 属性:
@Configuration
public class JpaConfig extends JpaBaseConfiguration {
@Autowired
private ConfigurableListableBeanFactory beanFactory;
protected JpaConfig(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
@Override
protected Map<String, Object> getVendorProperties() {
Map<String, Object> properties = new HashMap<>();
// This is the important line
properties.put(org.hibernate.cfg.AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
return properties;
}
}
--编辑-- 2. 的变体 SpringBeanContainer 或者,SpringBeanContainer 可以这样配置,好处是不会丢失 [=29] 的 Hibernate 属性=] 引导填充:
@Configuration
public class JpaConfig {
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
EntityManagerFactoryBuilder builder, ConfigurableListableBeanFactory beanFactory) {
return builder.dataSource(dataSource) //
.packages(BaseEntity.class) //
.persistenceUnit("myunit") //
.properties(Map.of(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory))) //
.build();
}
}
我已经通过 Sping Data JPA 实现了审计,但现在我希望能够控制更新并使用自定义逻辑创建时间戳。所以我想编写一个扩展 Auditingentitylistener 的自定义审计实体侦听器。
我有以下通用实体 class,我在其中注册了自定义审计实体侦听器:
@MappedSuperclass
@Audited
@EntityListeners(CustomAuditingEntityListener.class)
public class AuditableEntity extends BaseEntity {
@CreatedDate
@Column(name = "created", nullable = false)
private Date created;
@CreatedBy
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "created_by_id", foreignKey = @ForeignKey(name = "fk_entity_created_by_id"))
private Account createdBy;
@LastModifiedDate
@Column(name = "last_updated", nullable = false)
private Date lastUpdated;
@LastModifiedBy
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "last_updated_by_id", foreignKey = @ForeignKey(name = "fk_entity_last_updated_by_id"))
private Account lastUpdatedBy;
protected AuditableEntity() {
}
...
}
CustomAuditingEntityListener class 定义为
@Configurable
public class CustomAuditingEntityListener extends AuditingEntityListener {
public CustomAuditingEntityListener() {
super();
}
@Override
@PrePersist
public void touchForCreate(Object target) {
if (//custom logic) {
super.touchForCreate(target);
}
}
@Override
@PreUpdate
public void touchForUpdate(Object target) {
if (//custom logic) {
super.touchForUpdate(target);
}
}
}
自定义审计实体侦听器被正确调用,但是当 super.touchForCreate(target)
或 super.touchForUpdate(target)
被调用时,时间戳未设置,因为 AuditingEntityListener class 中的处理程序为空。
这是 AuditingEntityListener 的代码 class:
package org.springframework.data.jpa.domain.support;
@Configurable
public class AuditingEntityListener implements ConfigurableObject {
private ObjectFactory<AuditingHandler> handler;
public AuditingEntityListener() {
JoinPoint var2 = Factory.makeJP(ajc$tjp_1, this, this);
JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);
if (this != null && this.getClass().isAnnotationPresent(Configurable.class) && AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class))) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$before$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$e854fa65(this);
}
if ((this == null || !this.getClass().isAnnotationPresent(Configurable.class) || !AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class))) && this != null && this.getClass().isAnnotationPresent(Configurable.class) && AbstractDependencyInjectionAspect.ajc$iff1(var1)) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspectea6722c(this);
}
if (!AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class)) && AbstractDependencyInjectionAspect.ajc$iff1(var2)) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspectea6722c(this);
}
}
public void setAuditingHandler(ObjectFactory<AuditingHandler> auditingHandler) {
Assert.notNull(auditingHandler, "AuditingHandler must not be null!");
this.handler = auditingHandler;
}
@PrePersist
public void touchForCreate(Object target) {
if (this.handler != null) {
((AuditingHandler)this.handler.getObject()).markCreated(target);
}
}
@PreUpdate
public void touchForUpdate(Object target) {
if (this.handler != null) {
((AuditingHandler)this.handler.getObject()).markModified(target);
}
}
static {
ajc$preClinit();
}
}
有人可以解释我如何确保 AuditingHandler 不为 null 并且设置为默认 AuditingEntityListener class 吗?
在 Spring 5.1 中,有一种相当直接的方法可以在自定义实体侦听器中自动装配 Spring 组件,因此可以使用 AuditingHandler
。
1. 将客户实体侦听器声明为 Spring 组件。使用构造函数注入。
@Component
public class CustomAuditingEntityListener {
private ObjectFactory<AuditingHandler> handler;
public CustomAuditingEntityListener(ObjectFactory<AuditingHandler> auditingHandler) {
this.handler = auditingHandler;
}
@Override
@PrePersist
public void touchForCreate(Object target) {
if (//custom logic) {
AuditingHandler object = handler.getObject();
if (object != null) {
object.markCreated(target);
}
}
}
@Override
@PreUpdate
public void touchForUpdate(Object target) {
if (//custom logic) {
AuditingHandler object = handler.getObject();
if (object != null) {
object.markModified(target);
}
}
}
}
2. 通过设置适当的配置告诉 Hibernate 使用 Spring 作为 bean 提供者 属性:
@Configuration
public class JpaConfig extends JpaBaseConfiguration {
@Autowired
private ConfigurableListableBeanFactory beanFactory;
protected JpaConfig(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
@Override
protected Map<String, Object> getVendorProperties() {
Map<String, Object> properties = new HashMap<>();
// This is the important line
properties.put(org.hibernate.cfg.AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
return properties;
}
}
--编辑-- 2. 的变体 SpringBeanContainer 或者,SpringBeanContainer 可以这样配置,好处是不会丢失 [=29] 的 Hibernate 属性=] 引导填充:
@Configuration
public class JpaConfig {
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
EntityManagerFactoryBuilder builder, ConfigurableListableBeanFactory beanFactory) {
return builder.dataSource(dataSource) //
.packages(BaseEntity.class) //
.persistenceUnit("myunit") //
.properties(Map.of(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory))) //
.build();
}
}