Moves the existing virtual-thread/context-propagation project into context-propagation/ and adds method-security/ for the Spring Security 7 method-security article: nine runnable demos, fourteen assertions, and every transcript the article quotes, regenerated by scripts/run-all.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSrsDSRKVsY588yFiMJMo9
2.4 KiB
1. Why InheritableThreadLocal behaves differently with virtual threads
Next: Async + virtual threads →
Demo1PlainThreadLocal.java has no Spring in it at all. It exists to settle one question
before Spring Security enters the picture: does InheritableThreadLocal actually behave
differently once the thread on the other end is virtual?
The three cases
Every Thread copies the creating thread's InheritableThreadLocal values once, at
construction time. That single sentence explains everything Spring Security's concurrency
support has ever had to work around:
- A fresh platform
Threadpicks up whatever was set on the thread that created it. Fine. - A pooled platform thread was constructed once, long ago, by the pool's internal thread
factory. Every task submitted to it later runs on that same physical thread, so it keeps
whatever
InheritableThreadLocalvalue existed when the pool created the worker, not what the submitting thread had at submission time.docs/output/demo1.txtshows this directly: task 2 on a reused pool worker still reportsrequest-B, notrequest-C, even though the caller updated the value in between. - A virtual thread is, in this respect, identical to the fresh-platform-thread case.
Executors.newVirtualThreadPerTaskExecutor()andThread.ofVirtual().start(...)both construct a brand newThreadobject per task -- virtual threads are never pooled or reused the way platform worker threads are. So the "stale value from a reused thread" failure mode that madeSecurityContextHolder.MODE_INHERITABLETHREADLOCALdangerous withThreadPoolTaskExecutorsimply does not exist for virtual threads.
Why this matters for the rest of the repo
Spring Security's docs (and the original version of the blog post this repo supports) warn
against MODE_INHERITABLETHREADLOCAL because of the pooled-thread case above. That warning
is correct for ThreadPoolTaskExecutor. It stops being the relevant risk once
spring.threads.virtual.enabled=true swaps the executor for a SimpleAsyncTaskExecutor
backed by virtual threads -- there is no pool left to go stale. Chapter 2
verifies that directly against SecurityContextHolder.
Run it yourself: scripts/run-all.sh, or just demo1 from the output already captured in
docs/output/demo1.txt.