Deep Dive into Spring's @Autowired Annotation: Implementation and Injection Mechanism
This article provides a comprehensive analysis of Spring's @Autowired annotation, explaining its purpose, usage in constructor, field, and method injection, and detailing the underlying bean post‑processor logic, dependency resolution, and candidate selection that enable automatic dependency injection.
In everyday development, the @Autowired annotation is one of the most frequently used tools for automatically injecting Bean dependencies without manually creating objects with the new keyword.
The article examines the internal implementation of @Autowired in the Spring framework, describing its role as a dependency‑injection mechanism and showing how it can be applied to constructors, fields, and methods.
Example code for each injection style is provided:
@Component
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
} @Component
public class MyService {
@Autowired
private MyRepository repository;
} @Component
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}During container startup, Spring registers AutowiredAnnotationBeanPostProcessor , a built‑in post‑processor that handles properties and methods annotated with @Autowired . This processor intervenes in the bean initialization phase, particularly within the populateBean() method.
The core method postProcessProperties performs two main steps: (1) it discovers metadata for fields and methods marked with @Autowired , @Inject , or @Value ; (2) it injects the resolved dependencies into the bean instance.
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// <1> parse metadata for @Autowired, @Inject, @Value
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
// <2> inject dependencies via reflection
metadata.inject(bean, beanName, pvs);
return pvs;
}The injection logic ultimately relies on BeanFactory.resolveDependency , which delegates to doResolveDependency to locate candidate beans, handle collections, and apply qualifier annotations. If multiple candidates exist, determineAutowireCandidate selects the appropriate bean, preferring those annotated with @Primary , then @Priority , and finally falling back to matching by property name.
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
} else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set
autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
// <1> resolve bean from container
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// <2> inject via reflection
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}Overall, @Autowired achieves automatic bean injection through a combination of bean post‑processing, dependency resolution, and reflection. The candidate selection strategy first matches by type, then by qualifiers such as @Primary or @Priority , and finally by property name, ensuring flexible and maintainable dependency management.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
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.