Using Spring Transaction Synchronization Hooks to Send Kafka Messages After Commit
This article explains how to use Spring's TransactionSynchronizationManager to detect active transactions and register synchronization callbacks that asynchronously send Kafka messages only after a transaction commits, illustrated with a payment‑system case and complete Java code examples.
Preface
Today I want to share a little‑known technique: the hook functions of Spring transactions. To avoid a dry technical lecture, I will illustrate the correct usage with a concrete case.
Case Background
In a payment system we need to record each account's fund flow. The CTO requires that every write of a flow be pushed as a message to Kafka, and a separate archiving service consumes the message and persists it to a database that only the archiving service can write.
The process is simple: the payment service sends a Kafka message for each flow, and the archiving service stores it.
To avoid coupling with the integrator’s KafkaTemplate, the team decides to develop a second‑party library that provides a starter‑style API for sending messages to Kafka, supports transaction synchronization, and minimizes integration effort.
Solution
The key requirement is that sending the message must be transactional and must not affect the main business logic. The library should detect whether a transaction is active; if not, send the message asynchronously immediately; if a transaction is active, register a synchronization callback that sends the message after the transaction commits.
TransactionSynchronizationManager in Action
TransactionSynchronizationManager is a static utility class that holds a ThreadLocal set of TransactionSynchronization objects. The following pseudo‑code demonstrates how to use it:
private final ExecutorService executor = Executors.newSingleThreadExecutor();
public void sendLog() {
// Check whether a transaction is active
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
// No transaction – send the message asynchronously
executor.submit(() -> {
try {
// send message to Kafka
} catch (Exception e) {
// log exception, notify developers
}
});
return;
}
// Transaction is active – register a synchronization callback
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
// After commit, send the message asynchronously
executor.submit(() -> {
try {
// send message to Kafka
} catch (Exception e) {
// log exception
}
});
}
}
});
}The method isSynchronizationActive() returns true when a transaction has been started and the thread‑local variable has been populated by Spring’s transaction manager. The method registerSynchronization(...) adds a custom TransactionSynchronizationAdapter to the thread‑local set, allowing the library to execute custom logic after the transaction completes.
How to Determine Transaction Presence
The source code of TransactionSynchronizationManager.isSynchronizationActive() simply checks whether the internal ThreadLocal set is non‑null.
Spring activates the synchronization in TransactionSynchronizationManager.initSynchronization(), which is called by the transaction manager when a transaction begins.
How to Trigger Custom Logic After Commit
By registering a TransactionSynchronizationAdapter and overriding afterCompletion(int status), the library can run code only when status == TransactionSynchronization.STATUS_COMMITTED, i.e., after a successful commit.
Conclusion
When using TransactionSynchronizationManager, be careful not to switch threads between the transaction and the callback, otherwise the thread‑local data will be lost and the hook will not fire.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
