spring-projects / spring-data-commons

Spring Data Commons. Interfaces and code shared between the various datastore specific implementations.
https://spring.io/projects/spring-data
Apache License 2.0
771 stars 672 forks source link

Introduce standardized interfaces for published application events #3057

Open BriceRoncace opened 7 months ago

BriceRoncace commented 7 months ago

A possible enhancement to functionality detailed in the docs at https://docs.spring.io/spring-data/data-jpa/reference/data-commons/repositories/core-domain-events.html.

Any time, say, the save method is called (from CrudRepository), standard Spring created events (like Spring Data REST's BeforeSaveEvent and AfterSaveEvent) would be published. This would allow developers to create custom event handlers for standard lifecycle events without having to register custom events on those entities.

mp911de commented 7 months ago

The events you refer to are events provided by Spring Data REST (org.springframework.data.rest.core.event). In addition, each store module comes with their own events such as JPA's @PrePersist. Store-specific lifecycle events follow store semantics so for instance JPA events might be delayed until the transaction is closed.

Other stores like MongoDB or Cassandra emit events directly when updating or saving an object.

That being said, it doesn't make sense to introduce another mechanism over the existing ones. Let us know whether that helps.

BriceRoncace commented 7 months ago

Thank you @mp911de. In our use case we are exploring various ways to perform additional work right before an entity is saved (persisted or updated in JPA event terms). Our application is a traditional web application built with Spring Boot 3 (spring-boot-starter-web and spring-boot-starter-data-jpa); we are not using a specialized store, just a JPA compatible relational database.

We've tried:

This last point prompted this request. We fully agree with Oliver Drotbohm's statement:

Currently Spring Data JPA expects calls to ….save(…) as it's the only way we can reliably flag save point and issue the event distribution. It's the developer signaling, a set of state changes is really supposed to be persistent.

And organize our code in this way (i.e. explicitly calling repositories rather than relying on implicit changes to managed entities). But this limitation to JPA's lifecycle events prompted us to keep exploring options.

So, while I understand what you mean by introducing another event mechanism alongside the existing one (i.e., standard JPA events), I think having general-purpose, Spring domain events published by a Spring Data repository to signal that an entity was created, saved or deleted (like Spring Data REST) could be a nice way to standardize how Spring Data repositories behave within the Spring ecosystem (i.e., publishing application events). And, in our use case anyway, would eliminate some of the annoyances we have with JPA's lifecycle events not firing when we expect them to.

mp911de commented 7 months ago

Thanks for sharing your thoughts. There's indeed a impedance mismatch between the general repository abstraction and the lifecycle event handling. While repository interfaces are shared, events arose from store-specific implementations without a consolidation.

JPA clearly complicates the picture because JPA allows saving all sorts of things that aren't necessarily considered domain types by Spring Data.

We might come up with an interface-based approach to let our events implement these interfaces for a better abstraction.