Understanding the Implementation Mechanism of Spring's @Autowired Annotation
This article explains how Spring processes the @Autowired annotation by detailing the related classes, bean post‑processor interfaces, bean creation lifecycle, metadata collection, and property injection steps, complete with code examples and diagrams for deeper insight.
During an interview the author was asked about how Spring annotations work and responded by focusing on the @Autowired annotation, using it as a chance to demonstrate knowledge of its internal processing.
Interview technique advice is also given: avoid saying "I don't know" and steer the conversation toward familiar technologies.
@Autowired Related Classes
The core class that implements @Autowired functionality is AutowiredAnnotationBeanPostProcessor, which parses the annotation and performs automatic injection. Its inheritance hierarchy includes BeanPostProcessor, InstantiationAwareBeanPostProcessor, and MergedBeanDefinitionPostProcessor.
InstantiationAwareBeanPostProcessor Interface
Key methods:
postProcessBeforeInstantiation : called before bean instantiation; can return a bean instance (default returns null).
postProcessAfterInstantiation : called after bean creation but before property population; default returns true.
postProcessProperties : called before setting bean properties; default returns null.
@Nullable default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; } default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { return null; }MergedBeanDefinitionPostProcessor
This interface allows post‑processors to modify merged BeanDefinition objects. It defines two methods:
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName); void resetBeanDefinition(String beanName);AutowireCapableBeanFactory Interface
Extends BeanFactory and provides automatic injection capabilities. It defines four injection models:
AUTOWIRE_NO – no explicit injection model.
AUTOWIRE_BY_NAME – inject by bean name.
AUTOWIRE_BY_TYPE – inject by bean type.
AUTOWIRE_CONSTRUCTOR – inject via constructor.
The interface also declares createBean(Class<T> beanClass), which is invoked during bean creation.
<T> T createBean(Class<T> beanClass) throws BeansException;Bean Creation Lifecycle
Spring creates beans lazily. The process starts with getBean and proceeds through:
getBean
doGetBean
createBean
doCreateBean
populateBean
The crucial point for @Autowired is the createBean method in AbstractAutowireCapableBeanFactory, which eventually calls doCreateBean.
Collecting Injection Metadata
During bean creation,
AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinitionis invoked, which calls findAutowiringMetadata and then buildAutowiringMetadata to create an InjectionMetadata object that is cached in injectionMetadataCache.
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); } private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; }Setting Bean Properties
After metadata collection, populateBean is called, which invokes InstantiationAwareBeanPostProcessor.postProcessProperties. The AutowiredAnnotationBeanPostProcessor implementation retrieves the metadata and performs the actual injection.
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); ... if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); ... } } } } @Override 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) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; }Conclusion
The article walks through the classes involved in processing @Autowired, the steps of collecting injection metadata, and the points where Spring injects dependencies into beans. By studying the source of AutowiredAnnotationBeanPostProcessor and related interfaces, readers can deepen their understanding of Spring's dependency injection mechanism and even customize it.
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.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
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.
