What is BeanDefinitionRegistry and how do you build/register a definition with BeanDefinitionBuilder?
answer
- Registry = map of name → BeanDefinition
- DefaultListableBeanFactory implements it
- Builder = fluent genericBeanDefinition(...).addPropertyValue(...).getBeanDefinition()
- register inside BeanDefinitionRegistryPostProcessor
- override off by default in Boot
basics
~20 sBeanDefinitionRegistry 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 linespublic 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
Know registry stores definitions by name and Builder fluently creates one to register.
Name the core registry methods, that DefaultListableBeanFactory implements it, and the builder's key setters plus getBeanDefinition().
Explain the correct registration hook (BeanDefinitionRegistryPostProcessor) and override semantics/Boot default.
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).