A request-scoped proxy lets a singleton depend on an object selected from the active web request instead of storing one request's state globally.
Spring request scope proxy: resolve state for the current HTTP request
The Spring source kit uses Java 21 and its pinned Spring Boot dependencies. Run the named JUnit test to check this boundary.
Inject the proxy, not a captured request
The singleton ReceiptLabel reads its tenant from a proxied RequestTenant. The test binds request A and request B in turn, calls the same singleton, and observes different tenant labels. The singleton object identity stays stable while the request target changes.
Use a method call on the proxy. Direct field access reads a field on the proxy object and can bypass request-target lookup. The proxy does not authenticate either tenant. A production tenant must come from trusted identity and authorization rules, not an untrusted header stored in request scope.
No request context means no target
After the test clears RequestContextHolder, invoking the proxy throws a ScopeNotActiveException. That is expected for background work without an HTTP request. Capture a narrow authorized value and pass it explicitly to a task instead of retaining a request-scoped proxy in asynchronous work. Compare executor context boundaries.
Checked contract
class RequestTenant {
private String name;
void setName(String value) { name = value; }
String name() { return name; }
}
@Configuration
static class Config {
@Bean @RequestScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
RequestTenant requestTenant() { return new RequestTenant(); }
@Bean ReceiptLabel receiptLabel(RequestTenant tenant) { return new ReceiptLabel(tenant); }
}
record ReceiptLabel(RequestTenant tenant) {
String text() { return tenant.name; }
}How it is checked
RequestScopeBoundaryTest.resolvesASeparateTargetPerBoundRequest covers this behavior in the source kit. The displayed code is the test boundary; the kit contains its imports and configuration.
Costs and boundaries
One request target is retained per active request context, plus a singleton proxy. This local test does not measure concurrent traffic, session persistence or authentication; the scope ends with request cleanup.
Common Mistakes
- Do not put caller-provided tenant text into a trusted authorization decision.
- Do not call request-scoped targets from a background worker without an explicit context policy.
- Do not assume scoped proxy means the target itself is thread-safe.
Read next
Spring bean scopes: singleton identity is not thread safety, Spring task executors: capacity, rejection and lost context, Spring method authorization: test the proxied service boundary, Java ThreadLocal: clear request state on reused worker threads.
Continue with the new boundary checks
Continue with Spring session scope: one target across requests, separate targets across sessions.
