How do you inject a prototype bean into a singleton? (Pit… — Cracked Java
// Spring Framework & Spring Boot · Bean Scopes & Lifecycle
MidTheoryTrick

How do you inject a prototype bean into a singleton? (Pitfall + 4 solutions.)

The pitfall: a singleton is created and wired exactly once, so a prototype injected into it is resolved exactly once too — you get one prototype instance for the singleton's entire life, defeating the whole point of prototype scope. Naively @Autowired-ing a prototype into a singleton does not give you a fresh instance per use.

@Component
public class OrderService {           // singleton
    @Autowired private ReportBuilder builder;  // prototype — but wired ONCE

    void run() { builder.build(); }   // same instance every call. Bug.
}

There are four standard fixes. All share one idea: don't capture the instance — capture a way to ask the container for a new one.

1. ApplicationContextAware + getBean

Hold the context and look the bean up on each use. Works, but couples your code to the Spring API.

@Autowired private ApplicationContext ctx;
ReportBuilder fresh() { return ctx.getBean(ReportBuilder.class); }  // new each call

2. ObjectFactory / ObjectProvider

Inject a factory; call getObject() for a fresh instance. ObjectProvider (Spring 4.3+) adds null-safe / optional lookups.

@Autowired private ObjectProvider<ReportBuilder> builders;
void run() { builders.getObject().build(); }   // new each call

3. jakarta.inject.Provider

The JSR-330 equivalent — same pattern, standard API instead of a Spring type, which keeps your bean portable.

@Inject private Provider<ReportBuilder> builderProvider;
void run() { builderProvider.get().build(); }

4. @Lookup method injection

Declare an abstract/overridable method; Spring overrides it via CGLIB to return a fresh prototype each call. Cleanest at the call site.

@Lookup
protected ReportBuilder newBuilder() { return null; }  // Spring replaces the body
void run() { newBuilder().build(); }

A fifth option is a scoped proxy (@Scope(value="prototype", proxyMode=TARGET_CLASS)) on the prototype bean — the injected proxy resolves a new target per method call.

Mark your status