Understanding and Implementing Spring's @Autowired Annotation
This article explains the various ways to use Spring's @Autowired annotation, examines its underlying implementation via reflection, and provides detailed code examples illustrating field, constructor, setter, and collection injection, while also discussing annotation lifecycle and best practices.
Preface
When developing with Spring, there are two main configuration approaches: XML and Java config. As Spring Boot gains popularity, Java config and its annotations, especially @Autowired, become increasingly common for injecting defined beans.
@Autowired Annotation Usage
Before analyzing its implementation, let's review common @Autowired usage examples.
Constructor injection:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}Setter injection:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}Method injection with arbitrary name and multiple parameters:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}Field injection (most common) and mixed constructor/field injection:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}Injection into arrays, sets, and maps is also supported:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
} public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
} public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}What Does @Autowired Actually Do?
@Autowired belongs to Spring's container‑configuration annotations (alongside @Required, @Primary, @Qualifier, etc.). It signals the container to automatically wire a matching bean from the ApplicationContext into the annotated field, constructor, method, or parameter.
How @Autowired Is Implemented
The annotation is defined as:
package org.springframework.beans.factory.annotation;
import java.lang.annotation.*;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}The core processing logic resides in AutowiredAnnotationBeanPostProcessor. It scans candidate classes, builds InjectionMetadata for fields and methods annotated with @Autowired, and then injects the required dependencies during bean post‑processing.
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
// Process fields
ReflectionUtils.doWithLocalFields(targetClass, field -> {
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// Process methods
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
return;
}
if (method.getParameterCount() == 0) {
logger.warn("Autowired annotation should only be used on methods with parameters: " + method);
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
} while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}During bean creation, postProcessPropertyValues obtains the metadata and calls inject on each element, which uses reflection to set fields or invoke methods with the resolved bean instance.
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, beanName));
} else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, beanName));
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}Thus, @Autowired works by locating the appropriate bean in the container and injecting it via reflection, whether the target is a field or a method.
Key Takeaways
• @Autowired is a runtime annotation used for dependency injection in Spring beans. • It can be applied to constructors, methods, parameters, fields, and other annotations. • The injection process relies on reflection to set field values or invoke methods. • Static injection is discouraged because it breaks the instance‑based design of the container. • Understanding the underlying AutowiredAnnotationBeanPostProcessor helps developers troubleshoot injection issues and customize behavior if needed.
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.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.
