Add core-events module: @EventListener, @TransactionalEventListener phases and async listeners on Boot 4.1
Thirteen captured transcripts: a listener is a blocking method call, ordering and chaining, SpEL conditions, generic-event erasure, every transaction phase on commit and rollback, what an AFTER_COMMIT listener can write, which exceptions reach the publisher, async listeners on platform and virtual threads, and the annotations behind Spring Modulith's @ApplicationModuleListener. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Uu7q8vPeREyT4218EJPzz1
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# core-events
|
||||
|
||||
Companion project for the article **[Spring Application Events: @EventListener, @TransactionalEventListener and Async Events](https://ankurm.com/spring-application-events-eventlistener-transactionaleventlistener-async/)** on **[ankurm.com](https://ankurm.com)**.
|
||||
|
||||
Every console block quoted in the article came out of `output/`. Transcripts 01-11 are written by the test
|
||||
suite (so a claim that stops being true turns the build red); 12-13 are read out of jars by
|
||||
`scripts/capture-facts.sh`.
|
||||
|
||||
There is deliberately **no `docs/` folder**: the deeper material lives in collapsible "going deeper"
|
||||
sections inside the article itself, next to the paragraph each one extends.
|
||||
|
||||
## Versions
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Spring Boot | 4.1.1 |
|
||||
| Spring Framework | 7.0.9 |
|
||||
| JDK | 25 (Temurin 25.0.4.1+1) |
|
||||
| Maven | 3.9 |
|
||||
| H2 | the version Boot 4.1.1 manages |
|
||||
| Spring Modulith (javap only) | 2.1.1 |
|
||||
|
||||
## Quickstart
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/path/to/jdk-25
|
||||
mvn test # runs the scenarios and rewrites output/01-11
|
||||
./scripts/run-all.sh # everything, including 12-13 (needs network access to Maven Central once)
|
||||
```
|
||||
|
||||
## Source layout
|
||||
|
||||
Each scenario is its own package with its own `@SpringBootApplication`, which scans only that package, so a
|
||||
scenario starts with exactly the beans it shows and nothing else.
|
||||
|
||||
| Package | What it holds |
|
||||
|---|---|
|
||||
| `basics/` | `OrderService` publishes an `OrderPlaced` record; two listeners; the publisher blocks |
|
||||
| `ordering/` | `@Order` across two beans, an event returned from a listener, a listener that throws |
|
||||
| `conditional/`, `badcondition/` | SpEL `condition`s, and one that names a property that does not exist |
|
||||
| `generics/` | `Created<T>` and its erasure problem, and `ResolvableTypeProvider` |
|
||||
| `tx/` | one listener per transaction phase, a publisher that commits or rolls back, `fallbackExecution` |
|
||||
| `txwrite/` | an `AFTER_COMMIT` listener that writes: nothing declared, `REQUIRES_NEW`, plain `@Transactional` |
|
||||
| `asyncdemo/` | `@Async` listeners, the thread they land on, and what they see of the publisher's transaction |
|
||||
| `asyncplain/` | the same `@Async` listener in an application that forgot `@EnableAsync` |
|
||||
| `support/` | `Trace` (the in-memory log the tests print), `Modes`, and `Visibility` (asks "could another connection see this row?") |
|
||||
|
||||
## Captured output
|
||||
|
||||
| File | What it shows |
|
||||
|---|---|
|
||||
| `01-publish-is-a-method-call.txt` | a listener runs on the publisher's thread, before `publishEvent` returns |
|
||||
| `02-order-and-chaining.txt` | `@Order` across beans, an event returned from a listener, and a throwing listener stopping the rest |
|
||||
| `03-conditional-listeners.txt` | which SpEL-conditioned listeners ran for four events; the failure for a misspelled property |
|
||||
| `04-generic-events-and-erasure.txt` | a generic event that reaches no listener, and the `ResolvableTypeProvider` fix |
|
||||
| `05-transaction-phases-commit-and-rollback.txt` | every phase for a commit and for a rollback, with row visibility from another connection |
|
||||
| `06-no-transaction-drops-the-event.txt` | publishing outside a transaction, and `fallbackExecution` |
|
||||
| `07-after-commit-writes.txt` | an `AFTER_COMMIT` listener that inserts, declared three ways |
|
||||
| `08-exceptions-and-transactions.txt` | which listener's exception reaches the caller, and what it does to the row |
|
||||
| `09-async-listener-threads.txt` | an `@Async` listener on a platform thread, on a virtual thread, and with `@EnableAsync` forgotten |
|
||||
| `10-async-and-the-transaction.txt` | what an async listener can see of the publisher's transaction |
|
||||
| `11-async-exceptions.txt` | an async listener's exception: not the publisher's problem, but logged |
|
||||
| `12-modulith-application-module-listener.txt` | the annotations `@ApplicationModuleListener` is made of |
|
||||
| `13-transaction-cleanup-calls.txt` | the calls `DataSourceTransactionManager` makes when it cleans up |
|
||||
Reference in New Issue
Block a user