skip to content

What does SmartFactoryBean add over FactoryBean, and when would you choose a FactoryBean over a plain @Bean factory method?

level: principalimportance: nice to knowfreq 18%

answer

  1. SmartFactoryBean adds isPrototype() + isEagerInit()
  2. isEagerInit -> build product at startup, not lazily
  3. isPrototype true -> isSingleton ignored
  4. @Bean is the default; FactoryBean for library/framework
  5. product loses DI/init callbacks — cost of FactoryBean

basics

~20 s

SmartFactoryBean extends FactoryBean with isEagerInit() (create the singleton product eagerly at startup instead of lazily) and isPrototype() (mark the product as a prototype). Choose a FactoryBean over @Bean only for reusable, framework-level construction needing type introspection.

solid answer

~50 s

SmartFactoryBean<T> extends FactoryBean<T> with two extra hints: isPrototype() — declares the produced object is a prototype (overriding isSingleton semantics, so a fresh product per lookup); and isEagerInit() — asks the container to instantiate the singleton product eagerly during context refresh/pre-instantiation rather than lazily on first access. Both default to false. It's a niche interface used by infrastructure that wants finer control over eager creation. As for FactoryBean vs @Bean: a plain @Bean method is simpler and the Spring team's recommended default for application code — the returned object is a fully managed bean (DI, callbacks). Reach for a FactoryBean when writing reusable library/framework components, when you need the container to introspect the product type via getObjectType() before creation, when integrating third-party builders that fit the factory contract, or when '&'-dereference semantics are genuinely useful. Otherwise prefer @Bean.

code

java · 24 lines
java
import org.springframework.beans.factory.SmartFactoryBean;

public class EventPublisherFactoryBean implements SmartFactoryBean<EventPublisher> {

    @Override
    public EventPublisher getObject() {
        return new EventPublisher(); // opens a connection on construction
    }

    @Override
    public Class<?> getObjectType() { return EventPublisher.class; }

    @Override
    public boolean isSingleton() { return true; }

    // Force creation during context refresh so the connection is live at startup,
    // instead of lazily on first getBean(...).
    @Override
    public boolean isEagerInit() { return true; }

    // Not a prototype; one shared publisher.
    @Override
    public boolean isPrototype() { return false; }
}

go deeper

for a junior

Likely unaware of SmartFactoryBean; that's fine at this level.

for a middle

Should recognize SmartFactoryBean exists and that @Bean is usually simpler.

for a senior

Should explain isEagerInit vs lazy product creation and isPrototype overriding isSingleton.

for a principal

Should give crisp decision criteria for FactoryBean vs @Bean, cite real framework FactoryBeans, and weigh the lifecycle/introspection trade-offs.

## SmartFactoryBean<T> Defined in `org.springframework.beans.factory`, it extends `FactoryBean<T>` and adds two boolean hint methods (both `default false`): ```java public interface SmartFactoryBean<T> extends FactoryBean<T> { default boolean isPrototype() { return false; } default boolean isEagerInit() { return false; } } ``` ### isPrototype() Declares that the factory produces a **prototype** — a distinct product per request. Per the contract, if `isPrototype()` returns `true`, the `isSingleton()` result is effectively **disregarded** (the object is treated as non-singleton). It lets a factory positively assert prototype semantics rather than only implying it via `isSingleton()==false`. ### isEagerInit() By default a singleton FactoryBean's product is created **lazily** — only when first requested — even though the *factory* is instantiated at startup. `isEagerInit()` returning `true` tells the container to eagerly instantiate the **product** during singleton pre-instantiation at context refresh (`DefaultListableBeanFactory.preInstantiateSingletons`). Use it when the product must exist early (e.g., it starts a background resource, opens a pool, or registers listeners at startup) and you don't want to defer that to first access. ### Who uses it It's an SPI-flavored interface; most application code never implements it. Framework/infrastructure factories use it when they need to control eager creation or advertise prototype-ness precisely. ## FactoryBean vs @Bean factory method Both achieve "indirect construction," so which to use? **@Bean method (prefer by default):** - The returned object *is* a first-class managed bean: DI into it, `@PostConstruct`/`InitializingBean`, `@PreDestroy`/`DisposableBean`, full BeanPostProcessor pipeline, scopes, `@Primary`, conditions. - Simpler, colocated with configuration, easy to test. - The Spring reference explicitly recommends `@Bean`/`@Configuration` over writing FactoryBeans in application code. **FactoryBean (reach for it when):** - You're building a **reusable library/framework component** meant to be dropped into many contexts (this is why `LocalContainerEntityManagerFactoryBean`, `ProxyFactoryBean`, MyBatis `SqlSessionFactoryBean` are FactoryBeans). - You need the container to know the product **type up front** via `getObjectType()` for autowiring, before the product is built — a capability an `@Bean` method already gives via its return type, but a FactoryBean provides even when the concrete type is computed. - You want the **'&' dereference** ability so consumers can access the factory itself. - You're wrapping a third-party builder whose lifecycle maps naturally onto `getObject`/`getObjectType`/`isSingleton`. - You need eager/prototype hints via `SmartFactoryBean`. ## Trade-offs / gotchas - FactoryBean products **skip** DI and init callbacks (see the lifecycle question) — a real cost vs `@Bean`. - FactoryBeans add cognitive overhead and the two-object mental model; overusing them in app code is an anti-pattern. - Because an `@Bean` method's return type is statically known, it already gives Spring most of the type introspection benefit — so the type-introspection argument for FactoryBean mainly applies when the type is dynamic. - `isEagerInit()` interacts with lazy-init: it forces the product's creation at refresh even though FactoryBean products are otherwise lazy. ## Bottom line Use `@Bean` for application wiring; use `FactoryBean`/`SmartFactoryBean` for reusable, framework-level, dynamically-typed, or eager/prototype-controlled construction where the extra machinery earns its keep.

  • By default, is a singleton FactoryBean's product created eagerly at startup?
    No. The factory itself is instantiated at startup, but its product is created lazily on first access. isEagerInit() returning true (via SmartFactoryBean) is what forces the product to be created during singleton pre-instantiation at context refresh.
  • If SmartFactoryBean.isPrototype() returns true, what happens to isSingleton()?
    It is disregarded. isPrototype()==true asserts prototype semantics, so the product is treated as non-singleton regardless of what isSingleton() returns.
  • Why do the Spring docs recommend @Bean over writing your own FactoryBean?
    Because an @Bean method's returned object is a fully container-managed bean (DI, init/destroy callbacks, post-processing, scopes) and is simpler to write and test, whereas a FactoryBean product skips DI/init callbacks and adds a two-object mental model. FactoryBeans are meant for reusable framework/library construction, not everyday app wiring.

saying these in an interview costs you the question

  • Claiming FactoryBean is generally preferred over @Bean in application code
  • Saying isEagerInit() has no effect / confusing it with lazy-init on the factory
  • Thinking isPrototype() and isSingleton() both apply simultaneously
  • Inventing methods on SmartFactoryBean beyond isPrototype/isEagerInit

context