skip to content

Method Injection: @Lookup, lookup-method & replaced-method

@Lookup has the container override an abstract method so a singleton can obtain a fresh prototype on every call. Interviewers offer it as one answer to the prototype-in-singleton problem and ask how it compares with ObjectProvider.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What problem does method injection (@Lookup / lookup-method) solve when a singleton bean depends on a prototype bean?

level: juniorimportance: must knowfreq 62%

answer

  1. singleton created once -> prototype captured once
  2. inject a method, not an instance
  3. @Lookup / <lookup-method>
  4. CGLIB subclass overrides method -> getBean
  5. avoids ApplicationContextAware coupling

basics

~10 s

A singleton is created once, so a prototype injected normally is captured only once and reused forever. Method injection lets the singleton ask the container for a fresh prototype on every call.

solid answer

~40 s

A singleton bean is instantiated a single time, so any dependency injected into it — even a prototype — is resolved exactly once and the same instance is reused for the singleton's whole life. That defeats the point of a prototype, which should give a new object per request. Method injection fixes this: instead of injecting the prototype instance, you declare a lookup method that Spring overrides (via a CGLIB subclass) so each call returns a freshly resolved bean from the container. With @Lookup you annotate a (usually abstract) method; in XML you use <lookup-method>. This keeps the singleton a singleton while still handing it a new prototype every time the method runs, without the singleton needing a direct reference to the ApplicationContext.

go deeper

for a junior

Must grasp the 'singleton resolves its dependencies once' idea and that method injection gives a fresh instance per call.

for a middle

Should name @Lookup vs <lookup-method> and the CGLIB-subclass mechanism.

for a senior

Should compare against ObjectProvider/Provider and explain the ApplicationContextAware coupling being avoided.

for a principal

Should discuss when method injection is the wrong tool (prefer ObjectProvider) and CGLIB proxying constraints.

## The core problem: scope mismatch Spring beans have scopes. A **singleton** bean is created **once** by the container and cached; every injection point receives that same shared instance. A **prototype** bean is meant to produce a **brand-new instance every time it is requested**. Dependency injection happens **once, at bean-creation time**. So if you inject a prototype into a singleton the normal way (constructor or field), Spring resolves the prototype exactly once — when it builds the singleton — and stores that single instance in the singleton's field forever. Every method call on the singleton then reuses the *same* prototype object. The prototype's 'new instance per request' promise is silently broken. ```java @Component // singleton class Processor { @Autowired Task task; // prototype, but resolved ONCE — always the same object void run() { task.execute(); } // same task every time } ``` ## The fix: method injection Instead of injecting the *instance*, you inject a *method that fetches a fresh instance*. Spring supports this in two forms: - **`@Lookup`** (annotation): annotate a method — typically `abstract` — whose body Spring generates. Each invocation returns a newly resolved bean of the method's return type. - **`<lookup-method>`** (XML): the same mechanism declared in XML on a `<bean>`. Under the hood Spring creates a **CGLIB subclass** of your bean and overrides the lookup method to call `getBean(...)` on the container, so each call yields a fresh prototype. ```java @Component abstract class Processor { void run() { createTask().execute(); } // fresh Task each call @Lookup protected abstract Task createTask(); // Spring implements this } ``` ## Why not just inject ApplicationContext and call getBean? You can (`context.getBean(Task.class)`), and it works, but it couples your business class to the Spring container API — an anti-pattern that hurts testability and clarity. Method injection is the container-native way to express 'give me a fresh one each time' without that coupling. ## When to use it - A **long-lived (singleton) bean** needs a **shorter-lived (prototype) collaborator** on demand. - You want to avoid `ApplicationContextAware` / manual `getBean`. In modern code, injecting `ObjectProvider<Task>` / `Provider<Task>` and calling `getObject()` / `get()` is usually preferred (no CGLIB, no abstract methods) — but `@Lookup` remains the classic container-overridden approach and still appears widely.

  • If a singleton needs a fresh prototype each call, name two alternatives to @Lookup.
    Inject ObjectProvider<T> (or JSR-330 Provider<T>) and call getObject()/get() per request; or inject ApplicationContext/BeanFactory and call getBean() (works but couples code to the container). ObjectProvider is the modern preferred option.
  • Does method injection change the scope of the singleton?
    No. The outer bean stays a singleton — created once and cached. Only the lookup method returns a new instance per call; the singleton itself is not recreated.

saying these in an interview costs you the question

  • Claiming a prototype injected normally into a singleton gives a new instance each call
  • Saying @Lookup makes the enclosing bean a prototype
  • Believing you must inject ApplicationContext to get fresh prototypes

context

open as a page

How does the @Lookup annotation work, and what are the requirements on the method and bean it is used on?

level: middleimportance: must knowfreq 55%

basics

~10 s

You annotate a method (usually abstract) with @Lookup. Spring generates a CGLIB subclass that overrides it to return a fresh bean from the container each call. The class and method can't be final/private/static.

open as a page

When would you choose @Lookup / lookup-method over ObjectFactory/Provider (and vice versa) for obtaining prototype beans?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Both give a singleton fresh prototypes. @Lookup keeps a clean method call but needs CGLIB and non-final abstract-ish methods. ObjectFactory/Provider is a plain injected field with getObject()/get() — no CGLIB, easier to test, usually preferred today.

open as a page

Contrast XML <lookup-method> and <replaced-method>. What is the MethodReplacer interface and how do they relate to CGLIB?

level: seniorimportance: should knowfreq 34%

basics

~10 s

<lookup-method> makes Spring override a method to return a named bean each call — the XML form of @Lookup. <replaced-method> swaps a method's whole implementation with a MethodReplacer bean. Both use CGLIB subclassing.

open as a page

Because method injection relies on CGLIB subclassing, what constraints and failure modes must you anticipate, and how do you diagnose 'my @Lookup returns the same instance'?

level: principalimportance: should knowfreq 26%

basics

~20 s

CGLIB subclasses the bean, so it can't be final, the method can't be final/private/static, and the bean must be instantiable (not from a @Bean factory method). If none of that holds, Spring can't override the method and you get the original body / a stale singleton.

open as a page