skip to content

What is a BeanFactoryPostProcessor, and at what point in the container lifecycle does it run?

level: juniorimportance: must knowfreq 55%

answer

  1. definitions not instances
  2. runs before any bean instantiated
  3. postProcessBeanFactory(ConfigurableListableBeanFactory)
  4. don't call getBean — skips proxies
  5. PropertySourcesPlaceholderConfigurer is one

basics

~10 s

A BeanFactoryPostProcessor is a Spring hook that runs after the container reads all bean definitions but before it creates any beans. It can change the definitions (metadata), for example resolving ${...} placeholders.

solid answer

~40 s

A BeanFactoryPostProcessor (BFPP) is a container extension point that operates on bean *definitions* — the metadata Spring holds about each bean — not on bean instances. After the ApplicationContext loads every bean definition (from @Configuration, XML, component scan, etc.) but before it instantiates any singleton, Spring calls postProcessBeanFactory(ConfigurableListableBeanFactory). Inside, you can read and mutate definitions: change property values, alter scope, add or override attributes. The classic built-in is PropertySourcesPlaceholderConfigurer, which resolves ${...} placeholders against the Environment. Multiple BFPPs run ordered by PriorityOrdered, then Ordered, then the rest. The key rule: don't force bean instantiation from a BFPP, because beans created that early skip BeanPostProcessor treatment (like AOP proxying).

code

java · 16 lines
java
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MakeReportsLazy implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
        for (String name : bf.getBeanDefinitionNames()) {
            BeanDefinition bd = bf.getBeanDefinition(name);
            if (bd.getBeanClassName() != null && bd.getBeanClassName().endsWith("Report")) {
                bd.setLazyInit(true); // mutate metadata, no instance created
            }
        }
    }
}

go deeper

for a junior

Know it edits definitions before beans exist and that PropertySourcesPlaceholderConfigurer is an example.

for a middle

Explain the refresh() ordering (definitions loaded -> BFPPs -> BPPs registered -> singletons created) and the getBean anti-pattern.

for a senior

Contrast BFPP vs BPP crisply, discuss ordering (PriorityOrdered/Ordered) and premature-instantiation consequences.

for a principal

Discuss when custom BFPPs are justified vs configuration properties/conditions, and framework integrations that rely on definition mutation.

## What it is `BeanFactoryPostProcessor` (BFPP) is a functional interface in `org.springframework.beans.factory.config` with a single method: ```java void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory); ``` It is a **container extension point**. To understand it you need two concepts: - **BeanDefinition** — Spring does not create your beans directly from your classes. It first builds a `BeanDefinition` for each bean: an object holding the metadata (class name, scope, constructor args, property values, lazy flag, init/destroy methods, etc.). Think of it as the recipe, not the cake. - **Bean instance** — the actual object Spring later constructs from that recipe. A BFPP runs on the **recipes**, before any **cake** is baked. ## When it runs (lifecycle position) During `AbstractApplicationContext.refresh()`: 1. Bean definitions are loaded (parsing @Configuration, XML, scanning). 2. **`invokeBeanFactoryPostProcessors()`** — all BFPPs run here. At this moment every definition exists, but no application singleton has been instantiated yet. 3. `registerBeanPostProcessors()` — BeanPostProcessors are registered. 4. `finishBeanFactoryInitialization()` — non-lazy singletons are instantiated. So a BFPP sees the complete set of definitions and can still rewrite them before instantiation. ## What you can do inside - Resolve/override property values (e.g. inject computed values into definitions). - Change a bean's scope or lazy flag. - Add or remove property values / constructor args. - Inspect definitions to enforce conventions. Example: ```java public class ScopeEnforcer implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) { BeanDefinition bd = bf.getBeanDefinition("reportCache"); bd.setScope(BeanDefinition.SCOPE_SINGLETON); } } ``` ## The critical rule: don't instantiate beans A BFPP receives the `BeanFactory`, so it *can* call `getBean(...)`. Doing so is a well-known anti-pattern: it forces a bean to be created during BFPP processing, before `BeanPostProcessor`s (which do AOP proxying, `@Transactional`, `@Async`, etc.) are registered. That bean and anything it drags in get created **un-proxied**, silently breaking transactions/security/AOP. Only touch **definitions**, never instances. ## Ordering When several BFPPs exist, Spring runs them in this order: those implementing `PriorityOrdered`, then `Ordered`, then the remainder. Registry post-processors (see `BeanDefinitionRegistryPostProcessor`) run their registry phase even earlier. ## BFPP vs BeanPostProcessor Easy to confuse: - **BeanFactoryPostProcessor** — operates on **definitions**, runs **once**, before instantiation. - **BeanPostProcessor** — operates on **instances**, runs **per bean**, around initialization (`postProcessBeforeInitialization` / `AfterInitialization`), and is what enables proxying. ## When to use Rarely in application code — most needs are met by `@Value`, `@ConfigurationProperties`, profiles, and conditions. Reach for a BFPP when you must programmatically adjust *existing* definitions (mass property injection, framework/library integration). To *register new* definitions, use the `BeanDefinitionRegistryPostProcessor` sub-interface instead.

  • Why is calling getBean() inside a BFPP dangerous?
    It forces bean instantiation before BeanPostProcessors are registered, so those beans are created without AOP proxies — @Transactional, @Async, security advice, etc. silently stop working for them and anything they pull in.
  • What's the difference between a BeanFactoryPostProcessor and a BeanPostProcessor?
    BFPP operates on bean definitions (metadata), runs once before instantiation. BeanPostProcessor operates on bean instances, runs per-bean around initialization, and is what implements proxying/injection callbacks.

saying these in an interview costs you the question

  • Saying a BFPP modifies bean instances (it modifies definitions).
  • Claiming it runs after beans are created.
  • Thinking calling getBean() in a BFPP is harmless.
  • Confusing it with BeanPostProcessor.

context