Explain the three FactoryBean methods: getObject(), getObjectType(), and isSingleton().
answer
- getObject = product
- getObjectType = type for autowiring, null = costly
- isSingleton = container caches product
- default methods since 5.0 (null, true)
- factoryBeanObjectCache does the caching
basics
~20 sgetObject() 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 sgetObject() 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 linesimport 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
Should at least map each method to product / product-type / cache-or-not.
Should explain autowiring impact of getObjectType() and that the container caches singletons.
Should mention factoryBeanObjectCache, default methods since 5.0, and null-type eager-instantiation risk.
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