How Does Spring’s MergedBeanDefinitionPostProcessor Work? A Deep Dive

This article explains the role of Spring's MergedBeanDefinitionPostProcessor, showing how it merges bean definitions, invokes post‑processors during bean creation, and enables @Autowired‑related dependency injection with code examples and detailed workflow steps.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How Does Spring’s MergedBeanDefinitionPostProcessor Work? A Deep Dive

Environment

Spring Boot 2.3.12 RELEASE.

Purpose of MergedBeanDefinitionPostProcessor

The MergedBeanDefinitionPostProcessor merges bean definitions and allows post‑processors to modify them after the bean instance is created.

1. Setup Example

@Component
public class PersonDAOImpl implements PersonDAO {
    @Override
    public void save() {
        System.out.println("保存Person信息");
    }
}

@Service
public class UsersService {
    @Autowired
    private PersonDAO personDAO;

    public void saveUsers(Users users) {
        System.out.println("保存用户信息");
    }
}

2. Bean Creation

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    BeanWrapper instanceWrapper = null;
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // Allow post‑processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // invoke MergedBeanDefinitionPostProcessor after instance creation
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            } catch (Throwable ex) {
            }
            mbd.postProcessed = true;
        }
    }
}

3. Applying Merged Bean Definition Processors

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            ((MergedBeanDefinitionPostProcessor) bp)
                .postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }
}

The relevant BeanPostProcessor implementations are CommonAnnotationBeanPostProcessor (handles @PostConstruct, @PreDestroy, @Resource) and AutowiredAnnotationBeanPostProcessor (handles @Autowired, @Value, @Inject).

4. AutowiredAnnotationBeanPostProcessor Core Logic

public class AutowiredAnnotationBeanPostProcessor {
    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

    public AutowiredAnnotationBeanPostProcessor() {
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
        try {
            this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                ClassUtils.forName("javax.inject.Inject", getClass().getClassLoader()));
        } catch (ClassNotFoundException ex) {
            // JSR‑330 not available
        }
    }

    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
                                                Class<?> beanType, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz,
                                                    @Nullable PropertyValues pvs) {
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                    metadata = buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

    // buildAutowiringMetadata scans fields and methods for @Autowired, @Value, @Inject
}

5. Property Injection

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    metadata.inject(bean, beanName, pvs);
    return pvs;
}

Through these steps, Spring’s MergedBeanDefinitionPostProcessor enables the framework to resolve @Autowired and related annotations, cache metadata, and inject dependencies during bean creation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentSpring Bootdependency-injectionBeanPostProcessorSpring Framework
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.