Overview
Ive been asked several times to explain the difference between injecting Spring beans with @Resource,
@Autowired, and @Inject. While I received a few opinions from colleagues and read a couple of posts on
this topic I didnt feel like I had a complete picture.
Annotations
Annotation
@Resource
@Inject
@Qualifier
@Autowired
Package
Source
[Link]
Java
[Link]
Java
[Link]
Java
[Link] Spring
In order to explore the behavior of each annotation I fired up Spring Tool Suite and started debugging the
code. I used Spring [Link] in my research. The following is a summary of my findings.
The Code
I wanted to know how @Resource, @Autowired, and @Inject resolved dependencies. I created an
interface called Party and created two implementations classes. This allowed me to inject beans without
using the concrete type. This provided the flexibility I needed to determine how Spring resolves beans
when there are multiple type matches.
public interface Party {
Person is a component and it implements Party.
package [Link];
...
@Component
public class Person implements Party {
Organization is a component and it implements Party.
package [Link];
...
@Component
public class Organization implements Party {
I setup a Spring context that scans both of these packages for beans marked with @Component.
<context:component-scan base-package="[Link]"/>
<context:component-scan base-package="[Link]"/>
Tests
Test 1: Ambiguous Beans
In this test I injected a Party bean that has multiple implementations in the Spring context.
@Resource
private Party party;
@Autowired
private Party party;
@Inject
private Party party;
In all three cases a NoSuchBeanDefinitionException is thrown. While this exceptions name
implies that no beans were found, the message explains that two beans were found. All of
these annotations result in the same exception.
[Link]:
No unique bean of type [[Link]] is defined:
expected single matching bean but found 2: [organization, person]
Test 2: Field Name
In this test I named the Party field person. By default beans marked with @Component will have the same
name as the class. Therefore the name of the class Person is person.
@Resource
private Party person;
@Autowired
private Party person;
@Inject
private Party person;
@Resource can also take an optional name attribute. This is equivalent to the @Resource code above. In
this case the field variable name remains party. There is no equivalent syntax for @Autowired or
@Inject. Instead you would have to use a @Qualifier. This syntax will be covered later.
@Resource(name="person")
private Party party;
All four of these styles inject the Person bean.
Test 3: Field Type
In this test I changed the type to be a Person.
@Resource
private Person party;
@Autowired
private Person party;
@Inject
private Person party;
All of these annotations inject the Person bean.
Test 4: Default Name Qualifier
In this test I use a @Qualifier annotation to point to the default name of the Person component.
@Resource
@Qualifier("person")
private Party party;
@Autowired
@Qualifier("person")
private Party party;
@Inject
@Qualifier("person")
private Party party;
All of these annotations inject the Person bean.
Test 5: Qualified Name
I added a @Qualifier annotation to the Person class
package [Link];
...
@Component
@Qualifier("personBean")
public class Person implements Party {
In this test I use a @Qualifier annotation to point to the qualified name of the Person component.
@Resource
@Qualifier("personBean")
private Party party;
@Autowired
@Qualifier("personBean")
private Party party;
@Inject
@Qualifier("personBean")
private Party party;
All of these annotations inject the Person bean.
Test 6: List of Beans
In this test I inject a list of beans.
@Resource
private List<Party> parties;
@Autowired
private List<Party> parties;
@Inject
private List<Party> parties;
All of these annotations inject 2 beans into the list. This can also be accomplished with a
@Qualifier. Each bean marked with a specific qualifier will be added to the list.
Test 7: Conflicting messages
In this test I add a bad @Qualifier and a matching field name.
@Resource
@Qualifier("bad")
private Party person;
@Autowired
@Qualifier("bad")
private Party person;
@Inject
@Qualifier("bad")
private Party person;
In this case the field marked with @Resource uses the field name and ignores the
@Qualifier. As a result the Person bean is injected.
However the @Autowired and @Inject field throw a NoSuchBeanDefinitionException error
because it can not find a bean that matches the @Qualifier.
[Link]:
No matching bean of type [[Link]] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {@[Link](required=true),
@[Link](value=bad)}
Conclusions
With the exception of test 2 & 7 the configuration and outcomes were identical. When I looked under the
hood I determined that the @Autowired and @Inject annotation behave identically. Both of these
annotations use the AutowiredAnnotationBeanPostProcessor to inject dependencies. @Autowired and
@Inject can be used interchangeable to inject Spring beans. However the @Resource annotation uses the
CommonAnnotationBeanPostProcessor to inject dependencies. Even though they use different post
processor classes they all behave nearly identically. Below is a summary of their execution paths.
@Autowired and @Inject
1. Matches by Type
2. Restricts by Qualifiers
3. Matches by Name
@Resource
1. Matches by Name
2. Matches by Type
3. Restricts by Qualifiers (ignored if match is found by name)
While it could be argued that @Resource will perform faster by name than @Autowired and @Inject it
would be negligible. This isnt a sufficient reason to favor one syntax over the others. I do however favor
the @Resource annotation for its concise notation style.
@Resource(name="person")
@Autowired
@Qualifier("person")
@Inject
@Qualifier("person")
You may argue that they can be equal concise if you use the field name to identify the bean name.
@Resource
private Party person;
@Autowired
private Party person;
@Inject
private Party person;
True enough, but what happens if you want to refactor your code? By simply renaming the field name
youre no longer referring to the same bean. I recommend the following practices when wiring beans with
annotations.
Spring Annotation Style Best Practices
1. Explicitly name your component [@Component(beanName)]
2. Use @Resource with the name attribute [@Resource(name=beanName)]
3. Avoid @Qualifier annotations unless you want to create a list of similar beans. For example you may
want to mark a set of rules with a specific @Qualifier annotation. This approach makes it simple to
inject a group of rule classes into a list that can be used for processing data.
4. Scan specific packages for components [context:component-scan basepackage=[Link]]. While this will result in more component-scan configurations it
reduces the chance that youll add unnecessary components to your Spring context.