Spring Injection with @Resource, @Autowired and @Inject

August 1st, 2011 by David Kessler Leave a reply »

Overview

I’ve 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 didn’t feel like I had a complete picture.

Annotations

Annotation Package Source
@Resource javax.annotation Java
@Inject javax.inject Java
@Qualifier javax.inject Java
@Autowired org.springframework.bean.factory Spring



In order to explore the behavior of each annotation I fired up Spring Tool Suite and started debugging the code. I used Spring 3.0.5.RELEASE 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 com.sourceallies.person;
...
@Component
public class Person implements Party {
 
}

‘Organization’ is a component and it implements ‘Party’.

package com.sourceallies.organization;
...
@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="com.sourceallies.organization"/>
<context:component-scan base-package="com.sourceallies.person"/>

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 exception’s name implies that no beans were found, the message explains that two beans were found. All of these annotations result in the same exception.

org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No unique bean of type [com.sourceallies.Party] 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 com.sourceallies.person;
...
@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’.

 org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No matching bean of type [com.sourceallies.Party] found for dependency: 
expected at least 1 bean which qualifies as autowire candidate for this dependency. 
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(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 isn’t a sufficient reason to favor one syntax over the others. I do however favor the ‘@Resource’ annotation for it’s 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 you’re 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 base-package="com.sourceallies.person"]. While this will result in more component-scan configurations it reduces the chance that you’ll add unnecessary components to your Spring context.

Following these guidelines will increase the readability and stability of your Spring annotation configurations.

Related Links

Testing Spring Wiring
Beanoh Spring Wiring Test Framework

Advertisement

51 comments

  1. Bjorn says:

    Great article. Exactly what I was looking for.

    Thanks!

  2. Thank you. I have been using Autowired for some years. Now @ the new client site I have seen @Inject being used and was looking for differences. Your blog is refreshing in the sea of technical articles.

    Keep writing!!

  3. keerthi says:

    Fantastic article, shows all the differences about bean wiring.

  4. Amr Bedair says:

    Great … Exactly what I was looking for
    Many thanks…

  5. Peter B. says:

    that’s a great article! thanks a lot for sharing

  6. timothy brons says:

    awesome article! and no beating around the plant, i like when people tend to be straight to the point.

  7. Adriana says:

    thanks for share!

  8. kartheek says:

    Awesomes article. Cleared my mind

  9. Jon Bliss says:

    Good explanation. Many thanks.

  10. Krzysztof Kaczmarski says:

    awesome article!

  11. Dominic says:

    This is a great tutorial and flash the light on the complex model of DI in Spring .

  12. Kar Hoo says:

    Thanks for sharing such an interesting article.

    I’m glad to see that there are still developers for who a working piece of code just isn’t enough, and want to widen their understanding of the tools/frameworks they’re using.

  13. ash says:

    Thanks for sharing this interesting article.

  14. Pavan Chakka says:

    Nice article, well explained. Easy to understand.

  15. Hieu says:

    thanks for the article. It helps to clear thing up.

    On a side note, it’s a little pity that Spring did not utilize the params in @Resource such as name or mappedName to substitute the @Qualifier. It makes less typing for me :-).

  16. Mohammed Murtuza says:

    Awesome article! Cleared all my confusions..

  17. Brucebannor says:

    Very well written and informative! Keep up the excellent work. Very happy I found this article.

  18. dcheckoway says:

    It’s worth noting that @Resource can’t be used to annotate a constructor. @Autowired (and apparently @Inject) can.

    If you’re like me, you autowire constructors all over the place. It’s helps unit testing if you can pass mock objects to a constructor, rather than having to mock-autowire fields directly.

  19. Spencer says:

    Thanks. Needed exactly this for injecting multiple Configuration resources. I had @Autowired on constructors with Configuration arguments, got the “found 2″ message. Adding @Qualifier to each fixed the problem.

  20. Spencer says:

    @dcheckoway — use @Qualifier with the bean name on your constructor arguments. Works like a champ for me.

    E.g.

    @Autowired
    public DcDaoCass(@Qualifier(“cassandraConfiguration”) Configuration conf) throws ConfigurationException {

  21. Krishan Babbar says:

    Really nice article. Clearly define the differences.

  22. lutomas says:

    @Qualifier – is Spring annotation and it is in different package.

  23. Nate Buwalda says:

    Very informative and thorough. Thanks for doing the research.

  24. Sangala Shekhar Reddy says:

    Awesomes article!. Keep Writing..

  25. Ashish says:

    Very well explained!! great help.

  26. sv says:

    Clean and clear explanation.

  27. kent says:

    very good!

  28. Ondrej Medek says:

    You use Spring @Qualifier in your article, not the @javax.inject.Qualifier. The Java CDI has @Named anotation similar to Spring @Qualifier. The Java CDI @Qualifier has a different usage (and it has no value, see Javadoc).

  29. Chella says:

    Nicely written.Simple and very clear.

  30. alex says:

    Thank you for your research David!

  31. chandan says:

    awesome…stuff…….

  32. Sharath says:

    Thanks a lot man, thats helpful….

  33. If you want to have you @autowired list ordered you can implement the ordered interface to your bean. An example can be found here : http://rdafbn.blogspot.co.uk/2012/11/chain-of-responsibility-using-spring.html

  34. Prash says:

    Thank you … very helpful post.

  35. gundeep says:

    lucid explanation awesome

  36. Gary says:

    nice, I’m impressive~

  37. Mike says:

    Ditto on everyone else’s comments !

    Awesome article for a Spring newbie <= Me

    Was wondering how all these annotations fit together since there is so much overlap and multiple ways to do the same thing.

  38. Yuanjie Ding says:

    nice article and easy to understand,let us know the differences between them clearly thank you

  39. sumati says:

    amazing article!!! thanks

  40. Mariane Machado says:

    Excellent post ! Congrats !

  41. darli says:

    i m sure it must be
    @Qualifier of Spring pkg because for java @Qualifier it give below error in eclipse

    Usage:
    /** The manager. */
    @Inject
    @Qualifier(“test”) // javax.inject.Qualifier
    private EngineManager engManager;

    ERROR: The annotation @Qualifier is disallowed for this location

    but below is fine for spring
    @Inject
    @Qualifier(“test”)
    // org.springframework.beans.factory.annotation.Qualifier

  42. There is one more difference regarding Test 6

    If you have a bean definition like this

    @Bean
    public List parties ()
    {
    return new ArrayList();
    }

    you can inject the configured List with

    @Resource
    List parties;

    So parties.size() will be 0 in this case. This is not possible with @Autowired/@Inject as these are looking for a type match of Person and not List

  43. Given Nyauyanga says:

    Exactly what I needed. A thousand thanks :)

  44. Didi says:

    Thanks for the tips.

    I am not sure but this is against what I tackled :

    @Autowire is perfectly fitted for injection of generics classes.
    I have an abstract class ( AbstractController ) which uses a service interface ( Service ).
    With Spring, I make some instanciations of implemented classes ( ControllerA extends AbstractController, ControllerB extends AbstractController) – (same way with Service).

    Even though the @Autowire annotation is declared into abstract classes, it works. With @Resource, it doesn’t.

    I don’t dig the test further – maybe it isn’t the right cause – but it’s to notice.

  45. Eva says:

    Good explanation. tnx

  46. Ramki says:

    Awesome.. great article. please keep posted.

Leave a Reply

*