-
Notifications
You must be signed in to change notification settings - Fork 41.5k
Description
See sample code in branch to reproduce issue: https://github.com/caspianb/SpringBootTest/tree/feature/filter-proxy-bug
I reproduced this issue in at least the following spring boot versions (2.1.0, 2.1.4, 2.1.6, 2.1.7).
Spring is not properly injecting the proxied threadLocalTargetSource
for a prototype bean for the first Filter it injects the bean into. It seems ONLY Filter
classes have this issue -- if I do not enable filters (e.g. remove @Component
annotation from filters) in the above linked project the interceptor and user controller still work properly -- so it does not appear to simply be a "which class was loaded first" issue.
Starting the above sample application and accessing the root page will log output that demonstrates the issue:
- The first filter loaded by Spring will contain the direct
TenantStore
bean. - Every other component (including the second filter) will properly have the
proxiedLocalThreadTargetSource
TenantStore
bean.
Example of issue:
// First Request
[http-nio-8080-exec-1] INFO AuthFilterA: 1. TenantStore@1363509553 tenant=null
[http-nio-8080-exec-1] INFO AuthFilterA: 2. TenantStore@1363509553 tenant=John Doe
[http-nio-8080-exec-1] INFO AuthFilterB: 1. TenantStore@1280546379 tenant=null
[http-nio-8080-exec-1] INFO AuthFilterB: 2. TenantStore@1280546379 tenant=John Doe
[http-nio-8080-exec-1] INFO AuthInterceptor: 1. TenantStore@1280546379 tenant=John Doe
[http-nio-8080-exec-1] INFO AuthInterceptor: 2. TenantStore@1280546379 tenant=John Doe
[http-nio-8080-exec-1] INFO AuthController: TenantStore@1280546379 tenant=John Doe
[http-nio-8080-exec-1] INFO AuthInterceptor: 3. TenantStore@1280546379 tenant=John Doe
[http-nio-8080-exec-1] INFO AuthInterceptor: 4. TenantStore@1280546379 tenant=null
// Second Request
[http-nio-8080-exec-3] INFO AuthFilterA: 1. TenantStore@1363509553 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthFilterA: 2. TenantStore@1363509553 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthFilterB: 1. TenantStore@1703933351 tenant=null
[http-nio-8080-exec-3] INFO AuthFilterB: 2. TenantStore@1703933351 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthInterceptor: 1. TenantStore@1703933351 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthInterceptor: 2. TenantStore@1703933351 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthController: TenantStore@1703933351 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthInterceptor: 3. TenantStore@1703933351 tenant=John Doe
[http-nio-8080-exec-3] INFO AuthInterceptor: 4. TenantStore@1703933351 tenant=null
You can see AuthFilterA
has a different TenantStore
bean than all other beans. Further, this bean is maintained across all requests (since AuthFilterA
is a singleton holding onto a simple prototype bean).