DATAGRAPH-1061 - Register AuditingEventListener in post processor.
When using SpringBoot it will register all event listener in the context it can find in the SessionFactory. This will also include the Neo4jAuditionEventListener that would like to register itself. This leads to a dependency cycle in the bean creation. To get around this problem the registration will still be done in SpringBoot but the self-registration will be removed from the listener. If the listener is in the context, it will be registered with a previous de-registration in a new BeanPostProcessor. (cherry picked from commit caf0f5c)
This commit is contained in:
@@ -21,10 +21,9 @@ import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.neo4j.repository.support.Neo4jAuditingBeanFactoryPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Frantisek Hartman
|
||||
*/
|
||||
@@ -34,8 +33,9 @@ public class Neo4jAuditingEventListener extends EventListenerAdapter implements
|
||||
|
||||
/**
|
||||
* Creates a new {@link Neo4jAuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}
|
||||
* provided by the given {@link ObjectFactory}.
|
||||
*
|
||||
* provided by the given {@link ObjectFactory}. This constructor does an additional registration to the
|
||||
* {@link SessionFactory}. Therefore the {@link SessionFactory} must already be instantiated.
|
||||
*
|
||||
* @param auditingHandlerFactory must not be {@literal null}.
|
||||
*/
|
||||
public Neo4jAuditingEventListener(ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory,
|
||||
@@ -47,6 +47,17 @@ public class Neo4jAuditingEventListener extends EventListenerAdapter implements
|
||||
sessionFactory.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for creating an instance in the {@link Neo4jAuditingRegistrar} to get registered in the session
|
||||
* "manually". The registration is done within the {@link Neo4jAuditingBeanFactoryPostProcessor}.
|
||||
*
|
||||
* @param auditingHandlerFactory {@link AuditingHandler} to hook into the {@code preSave} phase for auditing.
|
||||
*/
|
||||
public Neo4jAuditingEventListener(ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory) {
|
||||
Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!");
|
||||
this.auditingHandlerFactory = auditingHandlerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreSave(Event event) {
|
||||
Object object = event.getObject();
|
||||
|
||||
@@ -13,19 +13,18 @@
|
||||
|
||||
package org.springframework.data.neo4j.repository.config;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
|
||||
import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.neo4j.annotation.EnableNeo4jAuditing;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* @author Frantisek Hartman
|
||||
*/
|
||||
@@ -65,8 +64,7 @@ public class Neo4jAuditingRegistrar extends AuditingBeanDefinitionRegistrarSuppo
|
||||
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(Neo4jAuditingEventListener.class);
|
||||
listenerBeanDefinitionBuilder
|
||||
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry))
|
||||
.addConstructorArgReference("sessionFactory");
|
||||
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
||||
|
||||
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
|
||||
Neo4jAuditingEventListener.class.getName(), registry);
|
||||
|
||||
@@ -20,8 +20,6 @@ import java.util.Optional;
|
||||
|
||||
import org.neo4j.ogm.annotation.NodeEntity;
|
||||
import org.neo4j.ogm.annotation.RelationshipEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -29,6 +27,7 @@ import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
|
||||
import org.springframework.data.neo4j.repository.Neo4jRepository;
|
||||
import org.springframework.data.neo4j.repository.support.Neo4jAuditingBeanFactoryPostProcessor;
|
||||
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean;
|
||||
import org.springframework.data.neo4j.repository.support.SessionBeanDefinitionRegistrarPostProcessor;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
@@ -53,6 +52,7 @@ public class Neo4jRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
|
||||
private static final String NEO4J_MAPPING_CONTEXT_BEAN_NAME = "neo4jMappingContext";
|
||||
private static final String NEO4J_ENTITY_INSTANTIATOR_CONFIGURATION_BEAN_NAME = "neo4jOgmEntityInstantiatorConfigurationBean";
|
||||
private static final String NEO4J_AUDITING_POST_PROCESSOR_NAME = "neo4jAuditionBeanFactoryPostProcessor";
|
||||
private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions";
|
||||
private static final String SESSION_BEAN_DEFINITION_REGISTRAR_POST_PROCESSOR_BEAN_NAME = "sessionBeanDefinitionRegistrarPostProcessor";
|
||||
private static final boolean HAS_ENTITY_INSTANTIATOR_FEATURE = ClassUtils.isPresent("org.neo4j.ogm.session.EntityInstantiator",
|
||||
@@ -164,6 +164,9 @@ public class Neo4jRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
registerIfNotAlreadyRegistered(new RootBeanDefinition(Neo4jMappingContextFactoryBean.class), registry,
|
||||
NEO4J_MAPPING_CONTEXT_BEAN_NAME, source);
|
||||
|
||||
registerIfNotAlreadyRegistered(new RootBeanDefinition(Neo4jAuditingBeanFactoryPostProcessor.class), registry,
|
||||
NEO4J_AUDITING_POST_PROCESSOR_NAME, source);
|
||||
|
||||
if (HAS_ENTITY_INSTANTIATOR_FEATURE) {
|
||||
registerIfNotAlreadyRegistered(new RootBeanDefinition(Neo4jOgmEntityInstantiatorConfigurationBean.class),
|
||||
registry, NEO4J_ENTITY_INSTANTIATOR_CONFIGURATION_BEAN_NAME, source);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.springframework.data.neo4j.repository.support;
|
||||
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
import org.neo4j.ogm.session.event.EventListener;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.data.neo4j.repository.config.Neo4jAuditingEventListener;
|
||||
|
||||
public class Neo4jAuditingBeanFactoryPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
@Autowired
|
||||
public Neo4jAuditingBeanFactoryPostProcessor(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof Neo4jAuditingEventListener) {
|
||||
EventListener auditingEventListener = (EventListener) bean;
|
||||
|
||||
// we need to de-register first to be sure we just register once.
|
||||
// Background: SpringBoot auto configuration does register all event listener in the context.
|
||||
sessionFactory.deregister(auditingEventListener);
|
||||
sessionFactory.register(auditingEventListener);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user