skip to content

Explain the three FactoryBean methods: getObject(), getObjectType(), and isSingleton().

level: middleimportance: must knowfreq 45%

answer

  1. getObject = product
  2. getObjectType = type for autowiring, null = costly
  3. isSingleton = container caches product
  4. default methods since 5.0 (null, true)
  5. factoryBeanObjectCache does the caching

basics

~20 s

getObject() returns the product bean. getObjectType() returns that product's class (or null if unknown) so Spring can autowire by type. isSingleton() tells Spring whether to build the product once and cache it (true) or call getObject() each time (false).

solid answer

~40 s

getObject() builds and returns the actual object the factory represents. getObjectType() reports the product's type up front — critical because Spring uses it for type-based autowiring and @Autowired candidate matching *without* instantiating the product; returning null forces Spring to instantiate the factory to learn the type, which can defeat lazy init and complicate matching. isSingleton() controls caching: if true (the default), the container calls getObject() once and caches the product in FactoryBeanRegistrySupport's factoryBeanObjectCache, returning the same instance thereafter; if false, getObject() is invoked on every lookup, yielding fresh products. Since Spring 5.0, getObjectType() and isSingleton() are default methods (returning null and true), so only getObject() is mandatory. A well-behaved implementation returns a stable, accurate getObjectType() to keep autowiring fast and correct.

code

java · 22 lines
java
import org.springframework.beans.factory.FactoryBean;

public class ClientFactoryBean implements FactoryBean<ApiClient> {

    private String baseUrl;
    public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; }

    @Override
    public ApiClient getObject() {
        return ApiClient.builder().baseUrl(baseUrl).build(); // complex construction
    }

    @Override
    public Class<?> getObjectType() {
        return ApiClient.class; // known up front -> fast autowiring by type
    }

    @Override
    public boolean isSingleton() {
        return true; // container caches the single ApiClient product
    }
}

go deeper

for a junior

Should at least map each method to product / product-type / cache-or-not.

for a middle

Should explain autowiring impact of getObjectType() and that the container caches singletons.

for a senior

Should mention factoryBeanObjectCache, default methods since 5.0, and null-type eager-instantiation risk.

for a principal

Should reason about stability contracts, product vs factory scope independence, and performance of getObject() in non-singleton factories.

## The contract ```java public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } } ``` (Since Spring 5.0 `getObjectType()` and `isSingleton()` have `default` implementations returning `null` and `true`; only `getObject()` is abstract.) ### getObject() Returns the object the factory produces — the thing that actually gets injected wherever the factory's bean id is referenced. It may run arbitrary construction logic (builders, proxies, conditional wiring). It can throw a checked `Exception`. It may return `null`, but that's discouraged and can cause injection failures. ### getObjectType() Returns the `Class<?>` of what `getObject()` will produce, **before** the product is created. This matters because: - Type-based autowiring (`@Autowired SomeType x`) needs to know each bean's type to pick candidates. For a FactoryBean, Spring reads `getObjectType()` to decide whether the product matches the injection point — *without* calling `getObject()*. - If it returns `null` (type not yet known), Spring may have to instantiate the factory (and possibly the product) to determine the type, which can trigger eager creation you wanted to avoid, or leave the bean unmatched during early type checks. Best practice: return the most specific stable type you can. If the type is only known after configuration, return it as early as possible. ### isSingleton() Controls whether the **product** is cached: - `true` (default): the container calls `getObject()` once, caches the result (in `FactoryBeanRegistrySupport.factoryBeanObjectCache`), and returns that same instance for every subsequent resolution. Note the *container* does the caching — your `getObject()` can naively `new` each call and the container will still hand out one cached instance. - `false`: the container calls `getObject()` on every lookup, so callers get fresh objects (prototype-like behavior for the product). Important subtlety: `isSingleton()` is expected to be **stable** for singleton FactoryBeans. If it returns `true`, the container assumes the product can be cached and won't re-query per call. Returning inconsistent values is a bug. ## Gotchas - Returning `null` from `getObjectType()` degrades autowiring-by-type and can force premature instantiation. - Assuming `isSingleton()==false` gives you full prototype bean lifecycle — it does not; it only means getObject() is re-invoked. No prototype destruction callbacks are managed for the product. - The factory's *own* scope (the factory bean) is independent from the product's singleton/prototype nature reported by `isSingleton()`. - Heavy work in `getObject()` for a non-singleton factory runs on every access — watch performance. ## When it matters Accurate `getObjectType()` is what lets Spring resolve `@Autowired` by type against FactoryBean products cleanly (e.g., autowiring an `EntityManagerFactory` produced by `LocalContainerEntityManagerFactoryBean`).

  • Why does returning null from getObjectType() hurt performance or correctness?
    Spring uses getObjectType() to match FactoryBean products against @Autowired-by-type injection points without instantiating them. If it returns null, Spring may have to instantiate the factory (and product) early to learn the type, defeating lazy initialization and complicating type matching.
  • If isSingleton() returns true but your getObject() does 'return new Foo()' each call, how many Foo instances exist?
    One. The container caches the first product in factoryBeanObjectCache and never calls getObject() again for that bean, so your naive 'new' runs only once.

saying these in an interview costs you the question

  • Thinking you must implement caching yourself for a singleton FactoryBean
  • Believing isSingleton()==false gives full prototype lifecycle for the product
  • Saying getObjectType() is optional with no consequences — null degrades autowiring

context