From 14542829c6e77cea77279a8fbfd5c172a717e60d Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Fri, 26 Jan 2018 14:51:00 +0100 Subject: [PATCH] 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 f0fe0f00cd9ad6037d63d16c93aed629b941e711) --- .../config/Neo4jAuditingEventListener.java | 19 +++++++++--- .../config/Neo4jAuditingRegistrar.java | 3 +- ...Neo4jRepositoryConfigurationExtension.java | 6 ++++ ...Neo4jAuditingBeanFactoryPostProcessor.java | 31 +++++++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/Neo4jAuditingBeanFactoryPostProcessor.java diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingEventListener.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingEventListener.java index 1191de171..056756cd6 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingEventListener.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingEventListener.java @@ -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 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 auditingHandlerFactory) { + Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!"); + this.auditingHandlerFactory = auditingHandlerFactory; + } + @Override public void onPreSave(Event event) { Object object = event.getObject(); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingRegistrar.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingRegistrar.java index 2e16637a2..3742b567a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingRegistrar.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jAuditingRegistrar.java @@ -64,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); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java index b261c3596..5b5a9c671 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/config/Neo4jRepositoryConfigurationExtension.java @@ -28,6 +28,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; @@ -50,6 +51,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_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"; @@ -159,5 +161,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); + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/Neo4jAuditingBeanFactoryPostProcessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/Neo4jAuditingBeanFactoryPostProcessor.java new file mode 100644 index 000000000..a78d9b5ab --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/Neo4jAuditingBeanFactoryPostProcessor.java @@ -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; + } +}