Skip to content

Commit a5047c9

Browse files
committed
Allow disabling entity lifecycle events.
We now support disabling lifecycle events through the Template API to reduce the framework overhead when events are not needed. Closes #1286
1 parent 20eb0f4 commit a5047c9

File tree

6 files changed

+183
-73
lines changed

6 files changed

+183
-73
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java

+36-24
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.concurrent.CompletionStage;
2121
import java.util.function.Consumer;
2222
import java.util.function.Function;
23+
import java.util.function.Supplier;
2324
import java.util.stream.Collectors;
2425
import java.util.stream.StreamSupport;
2526

@@ -124,7 +125,7 @@ public class AsyncCassandraTemplate
124125

125126
private final StatementFactory statementFactory;
126127

127-
private @Nullable ApplicationEventPublisher eventPublisher;
128+
private final EntityLifecycleEventDelegate eventDelegate;
128129

129130
private @Nullable EntityCallbacks entityCallbacks;
130131

@@ -190,11 +191,12 @@ public AsyncCassandraTemplate(AsyncCqlTemplate asyncCqlTemplate, CassandraConver
190191
this.entityOperations = new EntityOperations(converter);
191192
this.exceptionTranslator = asyncCqlTemplate.getExceptionTranslator();
192193
this.statementFactory = new StatementFactory(converter);
194+
this.eventDelegate = new EntityLifecycleEventDelegate();
193195
}
194196

195197
@Override
196198
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
197-
this.eventPublisher = applicationEventPublisher;
199+
this.eventDelegate.setPublisher(applicationEventPublisher);
198200
}
199201

200202
@Override
@@ -214,6 +216,18 @@ public void setEntityCallbacks(@Nullable EntityCallbacks entityCallbacks) {
214216
this.entityCallbacks = entityCallbacks;
215217
}
216218

219+
/**
220+
* Configure whether lifecycle events such as {@link AfterLoadEvent}, {@link BeforeSaveEvent}, etc. should be
221+
* published or whether emission should be suppressed. Enabled by default.
222+
*
223+
* @param enabled {@code true} to enable entity lifecycle events; {@code false} to disable entity lifecycle events.
224+
* @since 4.0
225+
* @see CassandraMappingEvent
226+
*/
227+
public void setEntityLifecycleEventsEnabled(boolean enabled) {
228+
this.eventDelegate.setEventsEnabled(enabled);
229+
}
230+
217231
@Override
218232
public AsyncCqlOperations getAsyncCqlOperations() {
219233
return this.cqlOperations;
@@ -456,11 +470,12 @@ private ListenableFuture<Boolean> doDelete(Query query, Class<?> entityClass, Cq
456470
tableName);
457471
SimpleStatement delete = builder.build();
458472

459-
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
473+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(delete, entityClass, tableName));
460474

461475
ListenableFuture<Boolean> future = doExecute(delete, AsyncResultSet::wasApplied);
462476

463-
future.addCallback(success -> maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName)), e -> {});
477+
future.addCallback(success -> maybeEmitEvent(() -> new AfterDeleteEvent<>(delete, entityClass, tableName)),
478+
e -> {});
464479

465480
return future;
466481
}
@@ -677,8 +692,8 @@ private ListenableFuture<WriteResult> doDeleteVersioned(Object entity, QueryOpti
677692

678693
if (!result.wasApplied()) {
679694
throw new OptimisticLockingFailureException(
680-
String.format("Cannot delete entity %s with version %s in table %s; Has it been modified meanwhile",
681-
entity, source.getVersion(), tableName));
695+
String.format("Cannot delete entity %s with version %s in table %s; Has it been modified meanwhile", entity,
696+
source.getVersion(), tableName));
682697
}
683698
});
684699
}
@@ -702,10 +717,11 @@ public ListenableFuture<Boolean> deleteById(Object id, Class<?> entityClass) {
702717
StatementBuilder<Delete> builder = getStatementFactory().deleteById(id, entity, tableName);
703718
SimpleStatement delete = builder.build();
704719

705-
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
720+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(delete, entityClass, tableName));
706721

707722
ListenableFuture<Boolean> future = doExecute(delete, AsyncResultSet::wasApplied);
708-
future.addCallback(success -> maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName)), e -> {});
723+
future.addCallback(success -> maybeEmitEvent(() -> new AfterDeleteEvent<>(delete, entityClass, tableName)),
724+
e -> {});
709725

710726
return future;
711727
}
@@ -719,10 +735,11 @@ public ListenableFuture<Void> truncate(Class<?> entityClass) {
719735
Truncate truncate = QueryBuilder.truncate(tableName);
720736
SimpleStatement statement = truncate.build();
721737

722-
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
738+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(statement, entityClass, tableName));
723739

724740
ListenableFuture<Boolean> future = doExecute(statement, AsyncResultSet::wasApplied);
725-
future.addCallback(success -> maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName)), e -> {});
741+
future.addCallback(success -> maybeEmitEvent(() -> new AfterDeleteEvent<>(statement, entityClass, tableName)),
742+
e -> {});
726743

727744
return new MappingListenableFutureAdapter<>(future, aBoolean -> null);
728745
}
@@ -753,7 +770,7 @@ private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIden
753770
private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName,
754771
SimpleStatement statement, Consumer<WriteResult> beforeAfterSaveEvent) {
755772

756-
maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, statement));
773+
maybeEmitEvent(() -> new BeforeSaveEvent<>(entity, tableName, statement));
757774
T entityToSave = maybeCallBeforeSave(entity, tableName, statement);
758775

759776
ListenableFuture<AsyncResultSet> result = doQueryForResultSet(statement);
@@ -766,7 +783,7 @@ private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIden
766783

767784
beforeAfterSaveEvent.accept(writeResult);
768785

769-
maybeEmitEvent(new AfterSaveEvent<>(entityToSave, tableName));
786+
maybeEmitEvent(() -> new AfterSaveEvent<>(entityToSave, tableName));
770787

771788
return writeResult;
772789
});
@@ -775,7 +792,7 @@ private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIden
775792
private ListenableFuture<WriteResult> executeDelete(Object entity, CqlIdentifier tableName, SimpleStatement statement,
776793
Consumer<WriteResult> resultConsumer) {
777794

778-
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
795+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
779796

780797
ListenableFuture<AsyncResultSet> result = doQueryForResultSet(statement);
781798

@@ -786,7 +803,7 @@ private ListenableFuture<WriteResult> executeDelete(Object entity, CqlIdentifier
786803

787804
resultConsumer.accept(writeResult);
788805

789-
maybeEmitEvent(new AfterDeleteEvent<>(statement, entity.getClass(), tableName));
806+
maybeEmitEvent(() -> new AfterDeleteEvent<>(statement, entity.getClass(), tableName));
790807

791808
return writeResult;
792809
});
@@ -864,9 +881,7 @@ public String getCql() {
864881
}
865882
}
866883

867-
return getAsyncCqlOperations()
868-
.execute(new GetConfiguredPageSize())
869-
.completable().join();
884+
return getAsyncCqlOperations().execute(new GetConfiguredPageSize()).completable().join();
870885
}
871886

872887
@SuppressWarnings("unchecked")
@@ -876,12 +891,12 @@ private <T> Function<Row, T> getMapper(Class<?> entityType, Class<T> targetType,
876891

877892
return row -> {
878893

879-
maybeEmitEvent(new AfterLoadEvent<>(row, targetType, tableName));
894+
maybeEmitEvent(() -> new AfterLoadEvent<>(row, targetType, tableName));
880895

881896
T result = getConverter().project(projection, row);
882897

883898
if (result != null) {
884-
maybeEmitEvent(new AfterConvertEvent<>(row, result, tableName));
899+
maybeEmitEvent(() -> new AfterConvertEvent<>(row, result, tableName));
885900
}
886901

887902
return result;
@@ -899,11 +914,8 @@ private static MappingCassandraConverter newConverter(CqlSession session) {
899914
return converter;
900915
}
901916

902-
protected <E extends CassandraMappingEvent<T>, T> void maybeEmitEvent(E event) {
903-
904-
if (this.eventPublisher != null) {
905-
this.eventPublisher.publishEvent(event);
906-
}
917+
protected <E extends CassandraMappingEvent<T>, T> void maybeEmitEvent(Supplier<E> event) {
918+
this.eventDelegate.publishEvent(event);
907919
}
908920

909921
protected <T> T maybeCallBeforeConvert(T object, CqlIdentifier tableName) {

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java

+32-21
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.List;
1919
import java.util.function.Consumer;
2020
import java.util.function.Function;
21+
import java.util.function.Supplier;
2122
import java.util.stream.Stream;
2223

2324
import org.apache.commons.logging.Log;
@@ -118,7 +119,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
118119

119120
private final StatementFactory statementFactory;
120121

121-
private @Nullable ApplicationEventPublisher eventPublisher;
122+
private final EntityLifecycleEventDelegate eventDelegate;
122123

123124
private @Nullable EntityCallbacks entityCallbacks;
124125

@@ -183,6 +184,7 @@ public CassandraTemplate(CqlOperations cqlOperations, CassandraConverter convert
183184
this.cqlOperations = cqlOperations;
184185
this.entityOperations = new EntityOperations(converter);
185186
this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter));
187+
this.eventDelegate = new EntityLifecycleEventDelegate();
186188
}
187189

188190
@Override
@@ -192,7 +194,7 @@ public CassandraBatchOperations batchOps(BatchType batchType) {
192194

193195
@Override
194196
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
195-
this.eventPublisher = applicationEventPublisher;
197+
this.eventDelegate.setPublisher(applicationEventPublisher);
196198
}
197199

198200
@Override
@@ -212,6 +214,18 @@ public void setEntityCallbacks(@Nullable EntityCallbacks entityCallbacks) {
212214
this.entityCallbacks = entityCallbacks;
213215
}
214216

217+
/**
218+
* Configure whether lifecycle events such as {@link AfterLoadEvent}, {@link BeforeSaveEvent}, etc. should be
219+
* published or whether emission should be suppressed. Enabled by default.
220+
*
221+
* @param enabled {@code true} to enable entity lifecycle events; {@code false} to disable entity lifecycle events.
222+
* @since 4.0
223+
* @see CassandraMappingEvent
224+
*/
225+
public void setEntityLifecycleEventsEnabled(boolean enabled) {
226+
this.eventDelegate.setEventsEnabled(enabled);
227+
}
228+
215229
@Override
216230
public CqlOperations getCqlOperations() {
217231
return this.cqlOperations;
@@ -488,11 +502,11 @@ WriteResult doDelete(Query query, Class<?> entityClass, CqlIdentifier tableName)
488502
tableName);
489503
SimpleStatement statement = delete.build();
490504

491-
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
505+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(statement, entityClass, tableName));
492506

493507
WriteResult writeResult = doExecute(statement);
494508

495-
maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName));
509+
maybeEmitEvent(() -> new AfterDeleteEvent<>(statement, entityClass, tableName));
496510

497511
return writeResult;
498512
}
@@ -700,8 +714,8 @@ private WriteResult doDeleteVersioned(SimpleStatement statement, Object entity,
700714

701715
if (!result.wasApplied()) {
702716
throw new OptimisticLockingFailureException(
703-
String.format("Cannot delete entity %s with version %s in table %s; Has it been modified meanwhile",
704-
entity, source.getVersion(), tableName));
717+
String.format("Cannot delete entity %s with version %s in table %s; Has it been modified meanwhile", entity,
718+
source.getVersion(), tableName));
705719
}
706720
});
707721
}
@@ -722,11 +736,11 @@ public boolean deleteById(Object id, Class<?> entityClass) {
722736
StatementBuilder<Delete> delete = getStatementFactory().deleteById(id, entity, tableName);
723737
SimpleStatement statement = delete.build();
724738

725-
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
739+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(statement, entityClass, tableName));
726740

727741
boolean result = doExecute(statement).wasApplied();
728742

729-
maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName));
743+
maybeEmitEvent(() -> new AfterDeleteEvent<>(statement, entityClass, tableName));
730744

731745
return result;
732746
}
@@ -740,11 +754,11 @@ public void truncate(Class<?> entityClass) {
740754
Truncate truncate = QueryBuilder.truncate(tableName);
741755
SimpleStatement statement = truncate.build();
742756

743-
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
757+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(statement, entityClass, tableName));
744758

745759
doExecute(statement);
746760

747-
maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName));
761+
maybeEmitEvent(() -> new AfterDeleteEvent<>(statement, entityClass, tableName));
748762
}
749763

750764
// -------------------------------------------------------------------------
@@ -795,27 +809,27 @@ private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName,
795809
private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName, SimpleStatement statement,
796810
Consumer<WriteResult> resultConsumer) {
797811

798-
maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, statement));
812+
maybeEmitEvent(() -> new BeforeSaveEvent<>(entity, tableName, statement));
799813
T entityToSave = maybeCallBeforeSave(entity, tableName, statement);
800814

801815
WriteResult result = doExecute(statement);
802816
resultConsumer.accept(result);
803817

804-
maybeEmitEvent(new AfterSaveEvent<>(entityToSave, tableName));
818+
maybeEmitEvent(() -> new AfterSaveEvent<>(entityToSave, tableName));
805819

806820
return EntityWriteResult.of(result, entityToSave);
807821
}
808822

809823
private WriteResult executeDelete(Object entity, CqlIdentifier tableName, SimpleStatement statement,
810824
Consumer<WriteResult> resultConsumer) {
811825

812-
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
826+
maybeEmitEvent(() -> new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
813827

814828
WriteResult result = doExecute(statement);
815829

816830
resultConsumer.accept(result);
817831

818-
maybeEmitEvent(new AfterDeleteEvent<>(statement, entity.getClass(), tableName));
832+
maybeEmitEvent(() -> new AfterDeleteEvent<>(statement, entity.getClass(), tableName));
819833

820834
return result;
821835
}
@@ -907,12 +921,12 @@ private <T> Function<Row, T> getMapper(EntityProjection<T, ?> projection, CqlIde
907921

908922
return row -> {
909923

910-
maybeEmitEvent(new AfterLoadEvent<>(row, targetType, tableName));
924+
maybeEmitEvent(() -> new AfterLoadEvent<>(row, targetType, tableName));
911925

912926
T result = getConverter().project(projection, row);
913927

914928
if (result != null) {
915-
maybeEmitEvent(new AfterConvertEvent<>(row, result, tableName));
929+
maybeEmitEvent(() -> new AfterConvertEvent<>(row, result, tableName));
916930
}
917931

918932
return result;
@@ -930,11 +944,8 @@ private static MappingCassandraConverter newConverter(CqlSession session) {
930944
return converter;
931945
}
932946

933-
protected <E extends CassandraMappingEvent<T>, T> void maybeEmitEvent(E event) {
934-
935-
if (this.eventPublisher != null) {
936-
this.eventPublisher.publishEvent(event);
937-
}
947+
protected <E extends CassandraMappingEvent<T>, T> void maybeEmitEvent(Supplier<E> event) {
948+
this.eventDelegate.publishEvent(event);
938949
}
939950

940951
protected <T> T maybeCallBeforeConvert(T object, CqlIdentifier tableName) {

0 commit comments

Comments
 (0)