Understanding and Implementing Spring's @Autowired Annotation

This article explains the various ways to use Spring's @Autowired annotation, explores its underlying implementation using reflection, analyzes the core processing classes in the Spring framework, and answers common questions about its lifecycle, bean relationships, and why static injection is discouraged.

Top Architect
Top Architect
Top Architect
Understanding and Implementing Spring's @Autowired Annotation

Introduction

When developing with Spring, configuration can be done via XML or Java config. As Spring Boot gains popularity, Java config and annotations like @Autowired become increasingly common for injecting beans defined in the container.

@Autowired Annotation Usage

The annotation can be applied to constructors, setter methods, arbitrary methods, fields, and even arrays, sets, or maps. Below are typical usage examples:

public class MovieRecommender {
    private final CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}
public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}
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 is the most common, but constructor injection is generally preferred for clearer dependencies.

What @Autowired Actually Does

@Autowired belongs to Spring's container‑configuration annotations. It signals the framework to automatically wire a matching bean from the ApplicationContext into the annotated field, method, or constructor at runtime.

Implementation Details

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 classes for fields and methods annotated with @Autowired, builds an InjectionMetadata object, and later injects the required beans.

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
    Class<?> targetClass = clazz;
    do {
        LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
        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));
            }
        });
        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);
}

The InjectionMetadata.inject method iterates over each InjectedElement and performs the actual injection using reflection, either by setting a field value or invoking a method.

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    for (InjectedElement element : injectedElements) {
        element.inject(target, beanName, pvs);
    }
}

For fields, ReflectionUtils.makeAccessible is used followed by field.set(target, value). For methods, the framework makes the method accessible and calls method.invoke(target, value).

Key Takeaways

The @Autowired annotation is a runtime‑retained marker that enables Spring to perform dependency injection via reflection. It works on constructors, methods, parameters, and fields, but not on static members because static injection would break the container‑managed lifecycle and testing practices.

Common Questions

Annotation lifecycle: Determined by the @Retention policy; @Autowired is retained at runtime.

Bean relationship: Injected beans become ordinary object references within the target bean, managed by the Spring container.

Why not static? Static fields belong to the class, not the instance, preventing the container from managing their lifecycle and hindering testability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaReflectionspringSpring Bootannotationsdependency-injectionAutowired
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.