A bean scope determines the ownership and reuse of instances created from a bean definition.
Spring bean scopes: singleton identity is not thread safety
This lesson uses the downloadable source kit: Java 21, Spring Boot 4.0.8 and its managed Spring Framework 7 dependencies. The version is pinned for repeatable builds.
Count instances at the ownership boundary
The report is a singleton in its context. ImportBuffer is prototype-scoped, and two provider resolutions return different instances. The test checks identity rather than comparing equal capacity values; equal values do not establish shared ownership.
A prototype injected once into a singleton remains that one injected reference. It does not turn into a new buffer on every method call. Use an explicit provider when a service genuinely requires a new instance per operation.
Shared mutable state needs its own rule
ReceiptStore is a singleton service. Its synchronized methods protect the map and identifier increment together, and page() returns an immutable snapshot. Removing the lock because Spring owns the service would create races in ordinary Java state.
Request and session scopes require a web-aware owner. Prototype objects with expensive resources need client cleanup; they do not inherit singleton destruction semantics. Before selecting a scope, decide who owns the resource and who can prove that ownership ended.
Checked source
context.registerBean(ImportBuffer.class, ImportBuffer::new,
definition -> definition.setScope(BeanDefinition.SCOPE_PROTOTYPE));
ObjectProvider<ImportBuffer> buffers = context.getBeanProvider(ImportBuffer.class);
boolean different = buffers.getObject() != buffers.getObject();Test the boundary
Run mvn test in the source-kit directory. CoreBoundaryTest checks the behavior described here. Java excerpts belong to the named source-kit classes; they are not independent source files unless the complete class is shown.
Costs and boundaries
Singleton reuse can reduce allocations while increasing contention on shared state. Prototype allocation grows with resolutions and may retain external resources until the caller releases them. The kit’s buffer contains no native resource.
Common Mistakes
- A singleton is not an automatic concurrency guarantee.
- Prototype injection into a singleton occurs at injection time.
- Do not assume prototype destruction is managed like singleton destruction.
Read next
Object provider, Lifecycle cleanup, Java threads: visibility, atomicity, and shared counters.
Next boundary checks
Continue with Spring request scope proxy: resolve state for the current HTTP request.
Continue with the new boundary checks
Continue with Spring session scope: one target across requests, separate targets across sessions.
