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 in this topic I didn ' t feel like I had a comple Te 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 all annotation I fired up Spring Tool Suite and started debugging the code. I used Spring 3.0.5.RELEASE in my. 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 II 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 is multiple type matches.
Public interface Party {} |
' Person ' was a component and it implements ' Party '.
Package Com.sourceallies.person, .... @Componentpublic class person implements party {} |
' Organization ' is a component and it implements ' Party '.
Package Com.sourceallies.organization, ... @Componentpublic 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"/> |
Teststest 1:ambiguous Beans
In this test I injected a ' Party ' bean, which 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, 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 beans but found 2: [Organization, person] |
Test 2:field Name
In this test I named the party field person. By default beans marked with ' @Component ' would have the same name as the class. Therefore the name of the class ' person ' is a person.
@Resourceprivate Party person; |
@Autowiredprivate Party person; |
@Injectprivate Party person; |
' @Resource ' can also take an optional ' name ' attribute. This was equivalent to the ' @Resource ' code above. The field variable name remains ' Party '. There is no equivalent syntax for ' @Autowired ' or ' @Inject '. Instead you would has to use a ' @Qualifier '. This syntax'll 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 is a ' person '.
@Resourceprivate Person Party; |
@Autowiredprivate Person Party; |
@Injectprivate 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.
@Resourceprivate list<party> Parties; |
@Autowiredprivate list<party> Parties; |
@Injectprivate list<party> Parties; |
All of these annotations inject 2 beans into the list. This can also is accomplished with a ' @Qualifier '. Each bean marked with a specific qualifier'll be added to the list.
Test 7:conflicting Messages
In the 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; |
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 beans 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 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 was found by name)
While it could is argued that ' @Resource ' would perform faster by name than ' @Autowired ' and ' @Inject ' it would be negligib Le. 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") |
Argue that they can is equal concise if you use the field name to identify the bean name.
@Resourceprivate Party person; |
@Autowiredprivate Party person; |
@Injectprivate 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
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 your want to mark a set of rules with a specific ' @Qualifier ' annotation. This approach makes it simple to inject a group of the rule classes into a list that can is used for processing data.
Scan Specific packages for components [Context:component-scan base-package= "Com.sourceallies.person"]. While this would result in more component-scan configurations it reduces the chance so you'll add unnecessary components to your Spring context.
Following these guidelines would increase the readability and stability of your Spring annotation configurations.
Attached: Chinese commentary
spring2.5 provides annotations (annotation-based)-based configuration, which we can use to complete injection dependencies. In Java code, you can use @Resource or @autowired annotations to line-inject. Although both @resource and @autowired can be used to complete the injection dependency, there is a difference between them. First Look at:
A. @Resource By default is assembled by name, only if the bean that matches the name is not found to assemble the injection according to the type;
B. @Autowired By default is injected by type assembly, if you want to transfer the injection by name, it needs to be used in conjunction with @qualifier;
C. @Resource annotations are provided by the Java EE, and @autowired is provided by spring, thus reducing the system's reliance on spring to recommend use
The way @Resource;
D. Both @Resource and @autowired can be written on the field or on the setter method of the field
2, the use of annotations, we need to modify the spring configuration file header information, modify some of the red label, as follows
<?xml version= "1.0" encoding= "UTF-8"?>
<beans xmlns= "Http://www.springframework.org/schema/beans"
Xmlns:xsi= "Http://www.w3.org/2001/XMLSchema-instance"
xmlns:context= "Http://www.springframework.org/schema/context"
Xsi:schemalocation= "Http://www.springframework.org/schema/beans
Http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
Http://www.springframework.org/schema/context
Http://www.springframework.org/schema/context/spring-context-2.5.xsd ">
<context:annotation-config/>
</beans>
3, after modifying the header information of the above configuration file, we can inject the bean in the Java code through annotations, see the following code
(1) @Resource
public class StudentService3 implements Istudentservice {
@Resource (name= "Studentdao") is also possible here.
Private Istudentdao Studentdao;
Private String ID;
public void SetId (String id) {
This.id = ID;
}
@Resource (name= "Studentdao")//Use this note to find a bean with the name Studentdao from the spring configuration file to assemble the field Studentdao if it does not exist in the spring configuration file The bean with the Studentdao name is shifted to the bean type by line lookup
public void Setstudentdao (Istudentdao Studentdao) {
This.studentdao = Studentdao;
}
public void Savestudent () {
Studentdao.savestudent ();
System.out.print (", ID:" +id);
}
}
The configuration file adds the following information
<bean id= "Studentdao" class= "Com.wch.dao.impl.StudentDao" ></bean>
<bean id= "StudentService3" class= "Com.wch.service.impl.StudentService3"/>
(2) @Autowired
public class StudentService3 implements Istudentservice {
It's also possible to put @Autowired here.
Private Istudentdao Studentdao;
Private String ID;
public void SetId (String id) {
This.id = ID;
}
@Autowired//Use this note to find beans that satisfy the Studentdao type from the spring configuration file
@Qualifier ("Studentdao") to find the transferred by name by line
public void Setstudentdao (Istudentdao Studentdao) {
This.studentdao = Studentdao;
}
public void Savestudent () {
Studentdao.savestudent ();
System.out.print (", ID:" +id);
}
}
The configuration file adds the following information
<bean id= "Studentdao" class= "Com.wch.dao.impl.StudentDao" ></bean>
<bean id= "StudentService3" class= "Com.wch.service.impl.StudentService3"/>
The Java code can be assembled using @autowire or @resource annotations, the differences between the two annotations are:
@Autowire By default assembly by type, by default it requires that the dependent object must exist if it is allowed to be null, you can set it required property to False, if we want to use by name assembly, can be used in conjunction with @qualifier annotations;
@Resource is assembled by name by default, when no bean matching the name is found to be assembled by type, it can be specified by the Name property, if the Name property is not specified, when the annotation is labeled on the field, that is, the default fetch field names as the bean name for the dependent object. When annotations are labeled on the setter method of the property, the default property name is used as the bean name for the dependent object.
Note: If the Name property is not specified, and the dependent object is still not found by default name, it will fall back to assembly by type, but once the Name property is specified, it can only be assembled by name.
Spring @Resource, @Autowired and @Inject injection