Understanding Spring Bean Instantiation: From Factory to AOP Proxy
This article walks through the Spring 5.3.3 bean creation process, detailing how the DefaultListableBeanFactory and AnnotationConfigApplicationContext initialize singleton beans, resolve bean definitions, apply post‑processors, handle AOP proxy generation, and complete bean initialization with aware interfaces and custom init methods.
Environment
Spring version 5.3.3 creates a DefaultListableBeanFactory when the container starts and instantiates an AnnotationConfigApplicationContext object.
1.1 Instantiating Singleton Beans
During refresh, the finishBeanFactoryInitialization method is invoked, which sets up conversion services, embedded value resolvers, load‑time weaver beans, freezes the configuration, and finally calls beanFactory.preInstantiateSingletons().
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
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)) {
// ...
} else {
getBean(beanName);
}
}
}
}The method checks whether each bean is a FactoryBean and otherwise retrieves the bean instance.
1.2 Getting Bean Objects
The parent class method AbstractBeanFactory.getBean(String name) delegates to doGetBean which eventually creates the bean instance.
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}1.3 Creating Bean Instances
The core method createBean(beanName, mbd, args) in AbstractAutowireCapableBeanFactory first attempts to obtain a proxy via resolveBeforeInstantiation. If a proxy is returned, it is used; otherwise the method proceeds to doCreateBean to instantiate the target object.
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
// ...
Object beanInstance = doCreateBean(beanName, mbd, args);
return beanInstance;
} resolveBeforeInstantiationruns all registered InstantiationAwareBeanPostProcessor instances (e.g., AnnotationAwareAspectJAutoProxyCreator) to possibly return a proxy before the actual bean is created.
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved) && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
Object bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
mbd.beforeInstantiationResolved = (bean != null);
return bean;
}
}
return null;
}The helper applyBeanPostProcessorsBeforeInstantiation iterates over all InstantiationAwareBeanPostProcessor implementations and returns the first non‑null result.
1.4 Populating Bean Properties
The populateBean method fills bean properties and invokes postProcessAfterInstantiation on each InstantiationAwareBeanPostProcessor. It then calls postProcessProperties to perform dependency injection for annotations such as @Resource, @Autowired, @Value, etc.
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// Property injection via postProcessProperties ...
}1.5 Initializing Bean
The initializeBean method applies Aware callbacks, runs BeanPostProcessor methods before and after initialization, and invokes custom init methods or afterPropertiesSet if the bean implements InitializingBean.
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
// handle exception
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}During the post‑initialization phase, AnnotationAwareAspectJAutoProxyCreator may create a proxy for beans that match AOP pointcuts.
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}The wrapIfNecessary method checks infrastructure classes, shouldSkip logic, and finally creates a proxy via createProxy when applicable.
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}The shouldSkip method looks for matching AspectJPointcutAdvisor instances, while findCandidateAdvisors gathers all advisor beans and AspectJ advisors from the factory.
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}Finally, createProxy builds a ProxyFactory, adds the collected advisors, sets the target source, and returns the generated proxy object, completing the bean's lifecycle.
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
proxyFactory.setFrozen(this.freezeProxy);
return proxyFactory.getProxy(getProxyClassLoader());
}At this point the bean instance is fully created, populated, initialized, and, if required, wrapped with an AOP proxy.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
