Unveiling Spring’s @Autowired vs @Resource: Deep Dive into Injection Mechanics
This article explains the fundamental differences between Spring's @Autowired and @Resource annotations, walks through their underlying source code, and demonstrates how Spring resolves dependencies by type or by name, complete with annotated code examples and processor internals.
Environment: Spring 5.3.23
1. Introduction
Both @Autowired and @Resource are used for dependency injection in Spring, but they follow different resolution strategies.
@Autowired
@Autowired is a Spring-provided annotation that injects dependencies primarily by type (byType). If multiple beans match the required type, Spring falls back to matching by bean name.
@Resource
@Resource comes from Jakarta EE and injects dependencies by name (byName) by default. If a name is not specified, it falls back to type‑based injection, and if neither name nor type is provided it attempts a reflective name‑based injection.
2. Source Code Analysis
Example code used for the demonstration:
static interface DAO {}
@Priority(1)
static class PersonDAO implements DAO {}
@Priority(2)
static class StudentDAO implements DAO {}
static class Service {
@Resource
// @Autowired
private DAO dao;
@Override
public String toString() {
return "Service [dao=" + dao + "]";
}
}2.1 @Resource Processing
The core processor for @Resource is CommonAnnotationBeanPostProcessor , which participates in the bean post‑processing phase to populate fields.
public abstract class AbstractAutowireCapableBeanFactory {
protected void populateBean(...) {
// @Resource handling is delegated to CommonAnnotationBeanPostProcessor
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
}
}
}The processor invokes CommonAnnotationBeanPostProcessor#postProcessProperties to handle the injection.
public class CommonAnnotationBeanPostProcessor {
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) {
// handle exception
}
return pvs;
}
}The InjectionMetadata class holds information about all fields that need injection.
public class InjectionMetadata {
private final Collection<InjectedElement> injectedElements;
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
for (InjectedElement element : injectedElements) {
element.inject(target, beanName, pvs);
}
}
}For @Resource, the concrete InjectedElement implementation is ResourceElement, which obtains the actual bean to inject via getResourceToInject.
private class ResourceElement extends LookupElement {
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
// Lazy handling omitted for brevity
return getResource(this, requestingBeanName);
}
}The CommonAnnotationBeanPostProcessor#getResource method ultimately delegates to the bean factory to resolve the dependency, first trying name‑based lookup and then falling back to type‑based resolution, considering @Primary and @Priority annotations when multiple candidates exist.
public class CommonAnnotationBeanPostProcessor {
private boolean fallbackToDefaultTypeMatch = true;
protected Object getResource(...) {
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
protected Object autowireResource(BeanFactory factory, LookupElement element, ...) {
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
if (fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
// resolve by type, then @Primary / @Priority
Object resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
return resource;
}
}
return null;
}
}2.2 @Autowired Processing
The core processor for @Autowired is AutowiredAnnotationBeanPostProcessor , which also uses InjectionMetadata to perform field injection.
public class AutowiredAnnotationBeanPostProcessor {
// similar structure to CommonAnnotationBeanPostProcessor
}During injection, AutowiredFieldElement#resolveFieldValue calls the bean factory’s resolveDependency method.
private class AutowiredFieldElement {
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
Object value;
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (Throwable ex) {
// handle exception
}
return value;
}
}The DefaultListableBeanFactory#resolveDependency method ultimately determines the appropriate bean, handling multiple candidates by checking @Primary, @Priority, and finally falling back to name matching.
public class DefaultListableBeanFactory {
public Object resolveDependency(...) {
return doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
public Object doResolveDependency(...) {
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
}
// further logic omitted for brevity
}
protected String determineAutowireCandidate(...) {
// checks @Primary, then @Priority, then name matching
}
}Through this detailed source‑code walkthrough, the article clarifies how Spring resolves @Resource and @Autowired annotations, highlighting the differences in default injection strategies and the fallback mechanisms that come into play when multiple beans match.
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.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.
