skip to content

What is BeanDefinitionRegistry and how do you build/register a definition with BeanDefinitionBuilder?

level: middleimportance: should knowfreq 40%

answer

  1. Registry = map of name → BeanDefinition
  2. DefaultListableBeanFactory implements it
  3. Builder = fluent genericBeanDefinition(...).addPropertyValue(...).getBeanDefinition()
  4. register inside BeanDefinitionRegistryPostProcessor
  5. override off by default in Boot

basics

~20 s

BeanDefinitionRegistry is the container's registry of BeanDefinitions keyed by bean name — it lets you register, remove, and look up definitions. BeanDefinitionBuilder is a fluent helper to construct a BeanDefinition, then you call registry.registerBeanDefinition(name, def).

solid answer

~30 s

`BeanDefinitionRegistry` is the SPI for holding bean definitions by name: `registerBeanDefinition(name, def)`, `removeBeanDefinition`, `containsBeanDefinition`, `getBeanDefinition`, `getBeanDefinitionNames`. `DefaultListableBeanFactory` (used by `GenericApplicationContext`) implements it, which is why post-processors receive it. `BeanDefinitionBuilder` is a fluent builder producing `GenericBeanDefinition`/`RootBeanDefinition`: `genericBeanDefinition(Class)`, then `addConstructorArgValue`, `addPropertyValue`, `addPropertyReference`, `setScope`, `setLazyInit`, `setInitMethodName`, `setPrimary`, `setAutowireMode`, finishing with `getBeanDefinition()`. You typically do this inside a `BeanDefinitionRegistryPostProcessor` or programmatic bootstrap, then register the result. It's the low-level metadata-model API for cases where annotations/XML can't express the wiring dynamically.

code

java · 17 lines
java
public class ReportBeansRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        BeanDefinition def = BeanDefinitionBuilder
                .genericBeanDefinition(ReportService.class)
                .addConstructorArgReference("dataSource")   // wire another bean
                .addPropertyValue("format", "PDF")
                .setScope(BeanDefinition.SCOPE_SINGLETON)
                .setLazyInit(true)
                .setPrimary(true)
                .getBeanDefinition();
        registry.registerBeanDefinition("reportService", def);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) { /* no-op */ }
}

go deeper

for a junior

Know registry stores definitions by name and Builder fluently creates one to register.

for a middle

Name the core registry methods, that DefaultListableBeanFactory implements it, and the builder's key setters plus getBeanDefinition().

for a senior

Explain the correct registration hook (BeanDefinitionRegistryPostProcessor) and override semantics/Boot default.

for a principal

Discuss real uses (Spring Data one-proxy-per-interface via registrars), constructor-arg indexing ambiguity, and definition vs instance separation in the factory.

## BeanDefinitionRegistry `org.springframework.beans.factory.support.BeanDefinitionRegistry` is the **contract for storing BeanDefinitions keyed by bean name**. Key methods: - `registerBeanDefinition(String beanName, BeanDefinition bd)` — add/replace a definition. - `removeBeanDefinition(String beanName)` — remove one (throws if absent). - `getBeanDefinition(String beanName)` — fetch the raw (unmerged) definition. - `containsBeanDefinition`, `getBeanDefinitionNames`, `getBeanDefinitionCount`. - `registerAlias` / `removeAlias` (via `AliasRegistry` superinterface). The primary implementation is **`DefaultListableBeanFactory`**, the bean factory inside `GenericApplicationContext`/`AnnotationConfigApplicationContext`. Because the factory *is* a registry, tooling and post-processors can enumerate and mutate definitions before beans are created. `SimpleBeanDefinitionRegistry` is a standalone map-based impl for utilities. Note: the registry deals with **definitions**, not instances. Singleton instances live in a separate singleton cache inside the factory. ## BeanDefinitionBuilder `org.springframework.beans.factory.support.BeanDefinitionBuilder` is a **fluent factory** for definitions so you don't hand-populate an `AbstractBeanDefinition`. Entry points: - `genericBeanDefinition(Class<?>)` / `genericBeanDefinition(String className)` — build a `GenericBeanDefinition`. - `rootBeanDefinition(Class<?>)` — build a `RootBeanDefinition`. - `childBeanDefinition(String parentName)` — build a child. Fluent setters (each returns the builder): - `addConstructorArgValue(Object)` / `addConstructorArgReference(String beanName)` - `addPropertyValue(String name, Object value)` / `addPropertyReference(String name, String beanName)` - `setScope(String)`, `setLazyInit(boolean)`, `setPrimary(boolean)` - `setInitMethodName`, `setDestroyMethodName` - `setAutowireMode(int)`, `setFactoryMethod`, `setRole`, `addDependsOn` - Terminal: `getBeanDefinition()` (or `getRawBeanDefinition()` before validation). ## Typical flow Build the definition, then register it against a `BeanDefinitionRegistry`. This is exactly what `@Import`ed `ImportBeanDefinitionRegistrar`s and `BeanDefinitionRegistryPostProcessor`s do internally, and what libraries like Spring Data use to register one repository proxy bean per interface. ## Gotchas - Register **before** the factory freezes/instantiates. Inside `postProcessBeanDefinitionRegistry` (of a `BeanDefinitionRegistryPostProcessor`) is the sanctioned hook; adding via `postProcessBeanFactory` or later is too late for clean participation. - `registerBeanDefinition` with an existing name **overrides** it if overriding is allowed; Spring Boot disables overriding by default (`spring.main.allow-bean-definition-overriding=false`), so a duplicate name throws. - Constructor arg **order/index** matters when a class has multiple constructors — use indexed args if ambiguous. - The builder produces metadata only; nothing is instantiated until the container creates the bean. ## When to use Dynamic/registration-heavy scenarios: framework/library code generating beans from external descriptors, one-bean-per-interface patterns, or conditional programmatic wiring that annotations can't express statically. For ordinary app beans, prefer annotations.

  • Which class implements BeanDefinitionRegistry in a typical ApplicationContext?
    DefaultListableBeanFactory — the internal bean factory of GenericApplicationContext/AnnotationConfigApplicationContext. Because the factory is also the registry, post-processors can enumerate and mutate definitions.
  • What happens if you register two definitions with the same bean name?
    The later one overrides the earlier, if overriding is enabled. Spring Boot disables it by default (allow-bean-definition-overriding=false), so a duplicate name throws a BeanDefinitionOverrideException.

saying these in an interview costs you the question

  • Confusing the definition registry with the singleton instance cache — they are separate.
  • Registering definitions after the context has already instantiated singletons and expecting them to participate.
  • Assuming duplicate names always silently override (Boot forbids it by default).

context