skip to content

BeanPostProcessor

A BeanPostProcessor can wrap or replace every bean as it initializes, which is exactly how AOP and @Async proxies appear. Explaining this is the difference between calling Spring magic and naming an extension point.

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

questions

4

What is a BeanPostProcessor in Spring and when do its methods run?

level: juniorimportance: must knowfreq 72%

answer

  1. Two callbacks bracket init phase
  2. before → @PostConstruct/afterPropertiesSet → after
  3. Return value replaces the bean (proxy swap)
  4. Applies to every bean in the factory
  5. Register = just declare it as a bean

basics

~10 s

A BeanPostProcessor is a Spring extension point with two callbacks that run on every bean after it is constructed and dependencies are injected — one just before the bean's init method, one just after.

solid answer

~40 s

BeanPostProcessor is a container extension interface with two methods: postProcessBeforeInitialization and postProcessAfterInitialization. Spring calls both on every bean it manages, once the bean has been instantiated and had its dependencies injected. 'Before' runs right before init callbacks (@PostConstruct, InitializingBean.afterPropertiesSet, custom init-method); 'After' runs right after them. Each method receives the current bean instance plus its name and returns a bean — usually the same instance, but it may return a different object, which lets Spring swap the bean for a proxy. This is exactly how framework features like AOP and @Async wrap your beans. You register one simply by declaring it as a @Bean or @Component; the container discovers and applies it automatically to all other beans.

code

java · 18 lines
java
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class TimingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        // runs before @PostConstruct / afterPropertiesSet / init-method
        return bean; // return same instance -> no change
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // runs after init; returning a different object swaps the bean
        return bean;
    }
}

go deeper

for a junior

Know the two method names and that they wrap the init phase of every bean.

for a middle

Explain the exact lifecycle ordering vs @PostConstruct/afterPropertiesSet and that the return value can replace the bean.

for a senior

Connect it to how AOP/@Async proxies are produced and the registration ordering during refresh.

for a principal

Discuss BPP self-processing exclusions, early-bean-instantiation hazards, and performance of per-bean logic.

## What it is `org.springframework.beans.factory.config.BeanPostProcessor` is one of Spring's core **container extension points**. It lets you run custom logic against **every bean** the container creates, at a well-defined moment in the bean's lifecycle. It is factory-scoped: a BeanPostProcessor (BPP) registered in an `ApplicationContext` sees all beans in that context. ## The two callbacks ```java Object postProcessBeforeInitialization(Object bean, String beanName); Object postProcessAfterInitialization(Object bean, String beanName); ``` Both are `default` methods (since Spring 5) returning the bean unchanged, so you override only the one you need. ## Where they sit in the lifecycle For a singleton, creation order is: 1. **Instantiate** (constructor). 2. **Populate properties** (dependency injection — fields/setters). 3. `Aware` callbacks (BeanNameAware, BeanFactoryAware, etc.). 4. **`postProcessBeforeInitialization`** — for every registered BPP. 5. **Initialization callbacks**: `@PostConstruct`, then `InitializingBean.afterPropertiesSet()`, then a custom `init-method`. 6. **`postProcessAfterInitialization`** — for every registered BPP. 7. Bean is now ready and stored in the singleton cache. So 'before' and 'after' bracket the **initialization** phase — not the constructor. The bean is already fully injected by the time either runs. ## Returning a different object The return value **replaces** the bean the container will use. Returning the same instance is the norm; returning a **wrapper/proxy** is the powerful case. Because `postProcessAfterInitialization` runs last and its return value is what gets cached and injected everywhere, it is the standard place to substitute a proxy — this is how Spring AOP (`AbstractAutoProxyCreator`) and `@Async` produce their proxies. Returning `null` from either method **aborts** further post-processing of that bean and returns whatever was produced so far. ## Registration Just make it a bean: annotate with `@Component`, or declare an `@Bean` method. `AbstractApplicationContext.refresh()` finds all `BeanPostProcessor` beans first (via `registerBeanPostProcessors`) and instantiates them **before** regular beans, so they exist to process everything else. ## Common uses - Wrapping beans in proxies (AOP, transactions, `@Async`, caching, security). - Reading/validating annotations and injecting values (`AutowiredAnnotationBeanPostProcessor`, `CommonAnnotationBeanPostProcessor` handle `@Autowired`/`@Resource`/`@PostConstruct` — themselves BPPs). - Auditing or wiring cross-cutting behavior uniformly. ## Gotchas - BPPs run for **every** bean, so keep the logic cheap and defensive (`instanceof` guards, name checks). - BPPs themselves are **not** post-processed by other BPPs, and beans they depend on may be created early (before all BPPs are registered), so keep their dependency graph minimal.

  • Does postProcessBeforeInitialization run before or after the constructor?
    After. The bean is already instantiated and its dependencies injected; the 'before' callback only precedes the initialization callbacks (@PostConstruct etc.), not the constructor.
  • How do you register a BeanPostProcessor?
    Declare it as a bean — @Component or an @Bean method. The container discovers all BeanPostProcessor beans during refresh and applies them to every other bean automatically.
  • What happens if a callback returns null?
    Spring uses the last non-null result and stops running further post-processors for that bean, which can break proxying. Always return a bean (the same one if you have no change).

saying these in an interview costs you the question

  • Saying the callbacks run before the constructor
  • Thinking BPPs apply only to some beans, not all
  • Confusing BeanPostProcessor with BeanFactoryPostProcessor (which edits definitions)

context

open as a page

What is the difference between postProcessBeforeInitialization and postProcessAfterInitialization, and why do proxies get created in the 'after' method?

level: middleimportance: should knowfreq 58%

basics

~10 s

'Before' runs just ahead of a bean's init callbacks; 'after' runs just after them. Proxies are created in 'after' so the wrapped object already had its @PostConstruct and afterPropertiesSet run on the real target.

open as a page

What does InstantiationAwareBeanPostProcessor add over a plain BeanPostProcessor?

level: seniorimportance: should knowfreq 40%

basics

~20 s

It adds hooks that fire around instantiation itself — before the constructor runs and after, during property population — whereas a plain BeanPostProcessor only wraps the later initialization phase. It can even short-circuit creation by returning a substitute object.

open as a page

What are the registration, ordering, and early-instantiation pitfalls of BeanPostProcessors?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

BPPs are created early, before normal beans, so any beans a BPP depends on get built early too — potentially before all BPPs are registered, so they may miss post-processing (e.g. not get proxied). Order BPPs with Ordered/PriorityOrdered; BPPs don't post-process each other.

open as a page