Inside Spring 6 Bean Creation: A Step‑by‑Step Deep Dive
This article walks through Spring 6.1.2’s bean creation lifecycle, from the refresh entry point to property population, initialization, and disposable bean registration, illustrating each step with concise code examples and detailed explanations.
Environment: Spring 6.1.2
1. Introduction
To avoid interference from other classes (BeanPostProcessor), we use a clean GenericApplicationContext that does not register built‑in BeanPostProcessors.
<code>public class Person {}
public static void main(String[] args) {
try (GenericApplicationContext context = new GenericApplicationContext()) {
context.registerBean(Person.class);
context.refresh();
System.out.println(context.getBean(Person.class));
}
}
</code>2. Core Entry Point
The container initialization starts at ConfigurableApplicationContext#refresh, which performs a series of steps.
<code>public abstract class AbstractApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
try {
// 1. Prepare refresh (initialize Environment, validate properties)
prepareRefresh();
// 2. Obtain fresh BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. Prepare BeanFactory (register special post‑processors)
prepareBeanFactory(beanFactory);
// 4. Post‑process BeanFactory
postProcessBeanFactory(beanFactory);
// 5. Invoke BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);
// 6. Register BeanPostProcessors
registerBeanPostProcessors(beanFactory);
// 7. Initialize message source
initMessageSource();
// 8. Initialize event multicaster
initApplicationEventMulticaster();
// 9. Refresh (subclass‑specific logic)
onRefresh();
// 10. Register listeners
registerListeners();
// 11. Instantiate all non‑lazy singleton beans
finishBeanFactoryInitialization(beanFactory);
// 12. Finish refresh (publish ContextRefreshedEvent)
finishRefresh();
}
}
}
</code>This article focuses on step 11 – the bean creation process.
3. Bean Creation Process
3.1 Traversing BeanDefinitions
<code>protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
beanFactory.preInstantiateSingletons();
}
</code>DefaultListableBeanFactory preInstantiateSingletons iterates over all bean definitions and obtains each bean.
<code>public class DefaultListableBeanFactory {
public void preInstantiateSingletons() {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
getBean(beanName);
}
} else {
getBean(beanName);
}
}
}
}
}
</code>3.2 Getting Instance from Singleton Pool
<code>protected <T> T doGetBean(String name, @Nullable Class<T> requiredType,
@Nullable Object[] args, boolean typeCheckOnly) {
String beanName = transformedBeanName(name);
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// return existing instance
} else {
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (Throwable ex) {
throw new BeansException("Failed to create bean", ex);
}
});
} else if (mbd.isPrototype()) {
// prototype handling
} else {
// other scopes
}
}
return (T) sharedInstance;
}
</code>3.3 Creating the Instance
3.3.1 Property Population
<code>protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
// Autowiring (byName, byType) omitted for brevity
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
</code>Example: CommonAnnotationBeanPostProcessor processes @Resource fields.
<code>public class CommonAnnotationBeanPostProcessor {
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (Throwable ex) {
// handle exception
}
return pvs;
}
}
</code>3.3.2 Initializing Bean
<code>protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// invoke init methods (afterPropertiesSet, custom init-methods)
invokeInitMethods(beanName, wrappedBean, mbd);
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
</code>3.3.3 Registering DisposableBean
<code>protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
}
}
}
</code>The DisposableBeanAdapter checks for DisposableBean, destroy methods, AutoCloseable, etc., to ensure proper cleanup.
Thus the complete bean initialization flow in Spring 6 is demonstrated.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.