- DtpPostProcessor: resolve the internal virtualThreadDelegate field once and trust
the executor instance whenever it exists, so a SimpleAsyncTaskExecutor running on
platform threads is no longer taken over just because spring.threads.virtual.enabled
is on. The global property is only used as a fallback on Spring < 6.1, where the
field does not exist.
- DtpPostProcessor: skip TaskScheduler beans (SimpleAsyncTaskScheduler extends
SimpleAsyncTaskExecutor), and honor @DynamicTp for pool naming on the virtual path.
- VirtualThreadExecutorProxy: register task statistics and the aware execute hook when
a task starts running instead of when it is submitted. decorate() is installed as the
TaskDecorator of the Spring bean and Spring may reject a task after decorating it
(closed executor, concurrency limit, thread creation failure), which used to leak the
active count and the performance stopwatch entry of a task that never ran. The reject
path therefore no longer rolls counters back, which also fixes a negative drift when
an already enhanced task was re-submitted.
- VirtualThreadExecutorProxy: keep the task wrapper adapted from the bean's TaskDecorator
in a dedicated field and merge it back in setTaskWrappers, so a config refresh that
resets the wrappers to taskWrapperNames cannot silently drop the user's decorator.
- AbstractDtpAdapter: skip pool-size validation and keepAlive tuning for virtual thread
executors, otherwise a tomcatTp config without core/max sizes made the whole refresh
(notify / taskWrapper / aware included) bail out when Tomcat runs on virtual threads.
- DtpRegistry: warn instead of silently ignoring a thread pool name conflict, the caller
would otherwise keep using an executor that is not managed at all.
- TomcatDtpAdapter: set the pool name on the virtual thread proxy.
- ReflectionUtil: add getFieldValue(Field, Object).
- Tests: cover platform-thread / TaskScheduler exclusion, decorate having no side effect
until the task starts, rejection after decoration not leaking counters, and the user
TaskDecorator surviving a config refresh.