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.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Understanding and Implementing Spring's @Autowired Annotation

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.

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.

BackendJavaReflectionspringdependency-injectionAutowired
Code Ape Tech Column
Written by

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

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.