Spring’s container API has three distinct layers: bean metadata, the factory that creates objects from that metadata, and an application context that coordinates the factory with application services. Keeping those layers separate makes Spring source code and extension points easier to reason about.
Bean Definitions and Registries #
BeanDefinition is mutable metadata for one bean. It records the bean class or
class name, scope, constructor arguments, property values, qualifiers, factory
method, lifecycle methods, role, source location, and explicit dependencies.
The parent/child metadata relationship is independent of Java inheritance.
Common implementations serve different registration paths:
RootBeanDefinitionrepresents a merged definition used by a bean factory.ChildBeanDefinitioninherits metadata from a named parent definition.GenericBeanDefinitioncan express either standalone or parent-derived metadata before merging.AnnotatedGenericBeanDefinitionexposes annotation metadata for a registered class.ScannedGenericBeanDefinitionexposes metadata read during classpath scanning without first loading the component class.
BeanDefinitionRegistry stores definitions by bean name. Its central operations
register, remove, and query definitions; DefaultListableBeanFactory and
GenericApplicationContext are important implementations.
AnnotatedBeanDefinitionReader registers explicitly supplied component classes:
var context = new GenericApplicationContext();
var reader = new AnnotatedBeanDefinitionReader(context);
reader.register(OrderService.class);
context.refresh();ClassPathBeanDefinitionScanner searches packages for candidate components and
registers their definitions. Both mechanisms apply annotation scope, naming,
qualifiers, conditions, and BeanDefinitionCustomizer callbacks. A customizer
can make a targeted metadata change during registration without implementing a
registry post-processor.
BeanFactory, FactoryBean, and ObjectFactory
#
BeanFactory is the runtime registry and dependency-resolution API. It locates
definitions, creates beans, resolves collaborators, manages singleton identity,
and applies lifecycle processors. ListableBeanFactory adds enumeration,
HierarchicalBeanFactory adds parent lookup, and
ConfigurableListableBeanFactory exposes container configuration to framework
infrastructure. Application code should depend on its domain collaborators
rather than call getBean() as a service locator.
Three similarly named types have different responsibilities:
- A
BeanFactoryis the container. - A
FactoryBean<T>is a bean that creates another object. Looking up its name returns the product; prefixing the name with&returns the factory itself.getObjectType()andisSingleton()describe the product. - An
ObjectFactory<T>is a minimal callback withgetObject(). Spring uses it for deferred retrieval and internal creation callbacks.ObjectProvider<T>extends the model with optional, ordered, and stream-based access.
The Application Context Hierarchy #
ApplicationContext extends ListableBeanFactory,
HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher,
ResourcePatternResolver, and related environment capabilities.
ConfigurableApplicationContext adds lifecycle operations such as refresh(),
close(), environment configuration, and access to the configurable factory.
AbstractApplicationContext implements the refresh algorithm. Specialized base
classes decide how definitions reach the factory:
GenericApplicationContextowns one internalDefaultListableBeanFactory. Definitions can be registered through its registry API before onerefresh()call.AnnotationConfigApplicationContextcombines a generic context with anAnnotatedBeanDefinitionReaderandClassPathBeanDefinitionScanner. Its constructors can register classes or scan packages and then refresh.- Servlet-aware contexts add web scopes and servlet resources but retain the same core factory contracts.
Some older context implementations recreate a bean factory during refresh,
while GenericApplicationContext does not support repeated refresh attempts.
Framework extensions must follow the concrete context’s lifecycle rather than
assume every context is refreshable more than once.
Refresh and Generated Definitions #
Annotation registration initially creates definitions for the supplied classes.
During refresh, ConfigurationClassPostProcessor parses @Configuration,
component scans, imports, and @Bean methods, then registers additional
definitions before ordinary beans are instantiated. Registry post-processors
can generate more definitions in the same phase. Spring’s AOT processing can
generate registration code ahead of time, but the resulting definitions still
feed the same bean-factory model.
ApplicationStartup instruments startup without changing lifecycle semantics.
DefaultApplicationStartup is a low-overhead no-op implementation,
BufferingApplicationStartup retains bounded step data, and
FlightRecorderApplicationStartup emits Java Flight Recorder events. A
StartupStep has a name, tags, and explicit end; custom infrastructure should
keep tags cheap because startup instrumentation runs on the critical path.
Choosing an Extension Point #
Use the narrowest layer that matches the requirement:
- Customize a definition at registration with
BeanDefinitionCustomizer. - Add or transform metadata with
BeanDefinitionRegistryPostProcessororBeanFactoryPostProcessor. - intercept instances with
BeanPostProcessor. - Build an object-producing bean with
FactoryBean. - Build a full coordinated container on
GenericApplicationContextor an application-context subtype.
Comments
Read or comment on GitHub (sign-in required to comment)