Overview
The article is to explain the difference between injecting Spring beans with ‘@Resource’, ‘@Autowired’, and ‘@Inject’.
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.
‘Person’ is a component and it implements ‘Party’.
‘Organization’ is a component and it implements ‘Party’.
I setup a Spring context that scans both of these packages for beans marked with ‘@Component’.
Tests
Test 1: Ambiguous Beans
In this test I injected a ‘Party’ bean that has multiple implementations in the Spring context.
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.
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’ 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.
All four of these styles inject the ‘Person’ bean.
Test 3: Field Type
In this test I changed the type to be a ‘Person’.
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.
All of these annotations inject the ‘Person’ bean.
Test 5: Qualified Name
I added a ‘@Qualifier’ annotation to the ‘Person’ class
In this test I use a ‘@Qualifier’ annotation to point to the qualified name of the ‘Person’ component.
All of these annotations inject the ‘Person’ bean.
Test 6: List of Beans
In this test I inject a list of beans.
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.
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’.
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
- Matches by Type
- Restricts by Qualifiers
- Matches by Name
@Resource
- Matches by Name
- Matches by Type
- 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.
You may argue that they can be equal concise if you use the field name to identify the bean name.
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
- Explicitly name your component [@Component("beanName")]
- Use ‘@Resource’ with the ‘name’ attribute [@Resource(name="beanName")]
- 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.
- 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.
reference : http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/#more-2350
No comments :
Post a Comment