I have an interface for a Service object that looks something like the following (simplified for brevity):
public interface ItemService {
public Item getItemB
Summarizing your question: You're looking for a transactionally-safe way to send messages.
Transactionally safe messaging is exactly what JMS is for. There's also good JMS integration in Spring, See the JMS chapter in the Spring documentation.
That will make sure that the messages are sent if and only if the transaction is committed. It also helps for dealing with errors in listeners for these events.
A difference with your current setup is that these events will be handled asynchronously: your service will return before these events have been handled. (JMS will make sure that they are processed eventually, it can be configured to try multiple times and how to deal with errors,...). Depending on your needs, that may be a good or a bad thing.
Alternatively, if JMS is too heavy-weight for your case, you could use transaction synchronization: When sending an event, instead of sending it directly use Spring's TransactionSynchronizationManager.registerSynchronization
, and send the message in the afterCommit()
of your TransactionSynchronization
.
You could either add a new synchronization per event to be sent, or add one synchronization and keep track of which events to be sent by binding an object containing that list to the transaction using TransactionSynchronizationManager.bindResource
.
I would advise against trying to use your own ThreadLocal
for this, because that would go wrong in some cases; for example if inside your transaction you would start a new transaction (RequiresNew
).
Differences with your current setup:
Alternatively, you can use beforeCommit
instead of afterCommit
, but then your events will be handled (mails sent,...) even if the actual commit to the database later fails.
This is less robust (less transactional), than using JMS, but lighter and easier to set up, and usually good enough.