本文主要介绍Spring Bean管理的依赖注入(Dependency Injection,DI)部分:基于Setter方法注入,构造函数注入,自动装配注入,@Autowired注解注入等。
所谓注入,就是给某一个bean实例的属性设值时,无需显性编写Java代码就可以实现属性赋值;所谓依赖注入,则通常指bean实例引用了其它实例,如常见的service引用dao,则对于service来说,用到的dao就需要依赖注入,spring ioc容器在创建service bean时会根据既定规则自动注入dao实例。
构造函数注入也就是通过构造方法注入依赖,构造函数的参数一般情况下就是依赖项,spring容器会根据bean中指定的构造函数参数来决定调用那个构造函数,看一个案例:
package com.marcus.spring.beans;
public class TextEditor {
private SpellChecker spellChecker;
private String generateType;
private String text;
@SuppressWarnings("rawtypes")
private List keywords;
public TextEditor() {
}
@SuppressWarnings("rawtypes")
public TextEditor(List list) {
System.out.println("Inside TextEditor constructor(list).");
this.keywords = list;
}
public TextEditor(SpellChecker spellChecker) {
System.out.println("Inside TextEditor constructor(checker).");
this.spellChecker = spellChecker;
}
public TextEditor(SpellChecker spellChecker, String generateType) {
System.out.println("Inside TextEditor constructor.");
this.spellChecker = spellChecker;
this.generateType = generateType;
}
public TextEditor(SpellChecker spellChecker, String generateType, String text) {
System.out.println("Inside TextEditor constructor(checker, generteType, text).");
this.spellChecker = spellChecker;
this.generateType = generateType;
this.text = text;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
public String getGenerateType() {
System.out.println("TextEditor generate type: " + this.generateType);
return this.generateType;
}
@SuppressWarnings("rawtypes")
public List getKeyWords() {
return this.keywords;
}
public void spellCheck() {
spellChecker.checkSpelling("TextEditor");
}
}
package com.marcus.spring.beans;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class SpellChecker {
@SuppressWarnings("rawtypes")
private List wordsList;
@SuppressWarnings("rawtypes")
private Set wordsSet;
@SuppressWarnings("rawtypes")
private Map wordsMap;
Properties wordsProp;
public SpellChecker() {
System.out.println("Inside SpellChecker constructor.");
}
public String checkSpelling(String text) {
String result = "success";
String errWords = "";
if (text == null || text.trim().length() < 1
|| wordsList == null || wordsList.size() < 1) {
return result;
}
String[] words = text.trim().split(",");
for(String word : words) {
if (word != null && word.trim().length() > 0) {
if(! wordsList.contains(word.trim().toLowerCase())) {
errWords += "".equals(errWords) ? word.trim() : "," + word.trim();
}
}
}
return errWords.length() < 1 ? result : errWords + " spells error!";
}
@SuppressWarnings("rawtypes")
public void setWordsList(List wordsList) {
this.wordsList = wordsList;
}
@SuppressWarnings("rawtypes")
public List getWordsList() {
System.out.println("List Elements :" + wordsList);
return wordsList;
}
@SuppressWarnings("rawtypes")
public void setWordsSet(Set wordsSet) {
this.wordsSet = wordsSet;
}
@SuppressWarnings("rawtypes")
public Set getWordsSet() {
System.out.println("Set Elements :" + wordsSet);
return wordsSet;
}
@SuppressWarnings("rawtypes")
public void setWordsMap(Map wordsMap) {
this.wordsMap = wordsMap;
}
@SuppressWarnings("rawtypes")
public Map getWordsMap() {
System.out.println("Map Elements :" + wordsMap);
return wordsMap;
}
public void setWordsProp(Properties wordsProp) {
this.wordsProp = wordsProp;
}
public Properties getWordsProp() {
System.out.println("Property Elements :" + wordsProp);
return wordsProp;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="textEditor" class="com.marcus.spring.beans.TextEditor">
<constructor-arg ref="spellChecker"/>
bean>
<bean id="textEditor2" class="com.marcus.spring.beans.TextEditor">
<constructor-arg ref="spellChecker"/>
<constructor-arg type="java.lang.String" value="constructor(checker, generatType)"/>
bean>
<bean id="textEditor3" class="com.marcus.spring.beans.TextEditor">
<constructor-arg ref="spellChecker"/>
<constructor-arg type="java.lang.String" index="1" value="constructor(checker, generatType)"/>
<constructor-arg type="java.lang.String" index="2" value="Text, Wood, SuperMen"/>
bean>
<bean id="textEditor4" class="com.marcus.spring.beans.TextEditor">
<constructor-arg type="java.util.List">
<list>
<value>INDIAvalue>
<value>Pakistanvalue>
<value>USAvalue>
list>
constructor-arg>
bean>
<bean id="spellChecker" class="com.marcus.spring.beans.SpellChecker" />
beans>
该配置文件定义了TextEditor的3个实例,对应TextEditor的3个构造函数。spring ioc容器会根据参数类型尝试查找合适的构造函数并创建TextEditor实例,因此<constructor-arg>的注入顺序并不重要。
请注意textEditor3,其构造函数后两个参数类型都是string,此时,我们必须标记参数位置索引index,否则对于spring ioc容器来说是一个灾难。
请注意textEditor4,其构造函数参数是一个集合,map、set等其它集合类似。
如果你想向一个对象传递一个引用,你需要使用标签的 ref 属性,如果你想直接传递值,那么你应该使用如上所示的 value 属性,如果参数是集合类型则参考textEditor4。
package com.marcus.spring.beans;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanDIApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di.xml");
System.out.println("=================================================");
TextEditor textEditor = context.getBean("textEditor", TextEditor.class);
System.out.println("textEditor: " + textEditor.toString());
TextEditor textEditor2 = context.getBean("textEditor2", TextEditor.class);
System.out.println("textEditor2: " + textEditor2.toString());
TextEditor textEditor3 = context.getBean("textEditor3", TextEditor.class);
System.out.println("textEditor3: " + textEditor3.toString());
System.out.println("textEditor3->text: " + textEditor3.getText());
TextEditor textEditor4 = context.getBean("textEditor4", TextEditor.class);
System.out.println("textEditor4: " + textEditor4.toString());
System.out.println("textEditor4->keywords: " + textEditor4.getKeyWords());
context.close();
}
}
Inside SpellChecker constructor.
Inside TextEditor constructor(checker).
Inside TextEditor constructor(checker, generteType).
Inside TextEditor constructor(checker, generteType, text).
Inside TextEditor constructor(list).
=================================================
textEditor: com.marcus.spring.beans.TextEditor@14bf9759
textEditor2: com.marcus.spring.beans.TextEditor@5f341870
textEditor3: com.marcus.spring.beans.TextEditor@589838eb
textEditor3->text: Text, Wood, SuperMen
textEditor4: com.marcus.spring.beans.TextEditor@544fe44c
textEditor4->keywords: [INDIA, Pakistan, USA]
构造函数循环依赖,class A构造时引用B,class B构造时引用A,就是循环依赖,这种情况下spring ioc容器无法实例化这两个bean,会报Is there an unresolvable circular reference?看一个案例:
package com.marcus.spring.beans;
public class LoopDependA {
private LoopDependB dependB;
public LoopDependA(){
}
public LoopDependA(LoopDependB dependB) {
this.dependB = dependB;
}
public void setDependency(LoopDependB dependB) {
this.dependB = dependB;
}
public LoopDependB getDependency() {
return this.dependB;
}
}
package com.marcus.spring.beans;
public class LoopDependB {
private LoopDependA dependA;
public LoopDependB() {
}
public LoopDependB(LoopDependA dependA) {
this.dependA = dependA;
}
public void setDependency(LoopDependA dependA) {
this.dependA = dependA;
}
public LoopDependA getDependency() {
return this.dependA;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="loopA" class="com.marcus.spring.beans.LoopDependA">
<property name="dependency" ref="loopB" />
bean>
<bean id="loopB" class="com.marcus.spring.beans.LoopDependB">
<property name="dependency" ref="loopA" />
bean>
beans>
构造函数循环依赖时,spring ioc容器无法实例化这2个bean,简单理解就是竞争锁,A实例化时需要B(B尚未实例化),B实例化需要A(A尚未实例化),A等B,B等A,谁也创建不了。
换成Setter注入,则可以,原因是Setter注入是在bean实例化完成之后通过调用set方法完成。因此,强烈不建议在配置文件中使用循环依赖。
package com.marcus.spring.beans;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* BeanApp.
*/
public class DILoopApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di-loop.xml");
LoopDependA loopA = context.getBean("loopA", LoopDependA.class);
System.out.println("LoopDependA->getDependency(), " + loopA.getDependency());
LoopDependB loopB = context.getBean("loopB", LoopDependB.class);
System.out.println("LoopDependB->getDependency(), " + loopB.getDependency());
context.close();
//输出结果
//LoopDependA->getDependency(), com.marcus.spring.beans.LoopDependB@77cd7a0
//LoopDependB->getDependency(), com.marcus.spring.beans.LoopDependA@204f30ec
}
}
- 引用类型请用标签的 ref 属性,简单值类型请用标签的value属性,如果是集合类型则参考上文的textEditor4实例配置
- 多个参数请设置type属性
- 多个参数类型一致时,如多个字符串等,请设置index属性
- 避免循环依赖
Setter注入顾名思义,被注入的属性需要有set方法, Setter注入支持简单类型、集合类型和引用类型,Setter注入时在bean实例创建完成后执行。Setter注入与构造函数注入唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。看一个案例:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="textEditor" class="com.marcus.spring.beans.TextEditor">
<property name="spellChecker" ref="spellChecker"/>
<property name="text" value="Text, Wood, SuperMen"/>
bean>
<bean id="textEditor2" class="com.marcus.spring.beans.TextEditor"
p:spellChecker-ref="spellChecker" p:text="Text, Wood, SuperMen, Compute"/>
<bean id="spellChecker" class="com.marcus.spring.beans.SpellChecker">
<property name="wordsList">
<list>
<value>textvalue>
<value>woodvalue>
<value>supermanvalue>
list>
property>
bean>
beans>
实例textEditor设置了2个属性:spellChecker和text,textEditor2功能等同textEditor,但是我们发现设置属性值时简单了很多。
可以使用 p-namespace 以一种更简洁的方式来设置bean属性值,要求配置文件必须引入xmlns:p=“http://www.springframework.org/schema/p”,参考textEditor2 bean配置。
spellChecker bean,使用了集合类型赋值,其它集合类型Map、Set等同理。
package com.marcus.spring.beans;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanDIApp2 {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di2.xml");
System.out.println("=================================================");
TextEditor textEditor = context.getBean("textEditor", TextEditor.class);
System.out.println("textEditor: " + textEditor.toString());
System.out.println("textEditor->checkText: " + textEditor.getText());
System.out.println("textEditor->spellCheck: " + textEditor.spellCheck());
TextEditor textEditor2 = context.getBean("textEditor2", TextEditor.class);
System.out.println("textEditor2: " + textEditor2.toString());
System.out.println("textEditor2->checkText: " + textEditor2.getText());
System.out.println("textEditor2->spellCheck: " + textEditor2.spellCheck());
context.close();
}
}
Inside TextEditor constructor().
Inside SpellChecker constructor.
Inside TextEditor constructor().
=================================================
textEditor: com.marcus.spring.beans.TextEditor@29ca901e
textEditor->checkText: Text, Wood, SuperMen
textEditor->spellCheck: SuperMen spells error!
textEditor2: com.marcus.spring.beans.TextEditor@5649fd9b
textEditor2->checkText: Text, Wood, SuperMen, Compute
textEditor2->spellCheck: SuperMen,Compute spells error!
- Setter注入与构造函数注入唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素
- 如果你要把一个引用传递给一个对象,那么你需要使用标签的 ref 属性,而如果你要直接传递一个值,那么你应该使用 value 属性,集合类型则需要使用property
- 可以使用 p-namespace 以一种更简洁的方式来设置bean属性值
上文已经介绍如何使用〈bean〉元素来声明 bean 和通过使用 XML 配置文件中的〈constructor-arg〉和〈property〉元素来注入 。Spring 容器可以在不使用〈constructor-arg〉和〈property〉元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写Bean配置文件的时间,有byName,byType,constructor三种装配模式。
模式 | 描述 |
---|---|
no | 这是默认的设置,它意味着没有自动装配。 |
byName | 由属性名自动装配。 |
byType | 由属性数据类型自动装配。 |
constructor | 类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。 |
自动装配确实可以减少bean定义文件代码编写,也无需关心引用的id或name是否写错,但是自动装配也有其缺陷和局限性:
- 不能自动装配所谓的简单类型包括基本类型,字符串和集合类
- 自动装配不如显式装配精确,所以如果可能的话尽可能使用显式装配
自动装配的一个案例,如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="textEditor" class="com.marcus.spring.beans.TextEditor" autowire="byName">
<property name="text" value="Text, Wood, SuperMen" />
<property name="generateType" value="autoWire = byName" />
bean>
<bean id="textEditor2" class="com.marcus.spring.beans.TextEditor" autowire="byType">
<property name="text" value="Text, Wood, SuperMen, byType" />
<property name="generateType" value="autoWire = byType" />
bean>
<bean id="textEditor3" class="com.marcus.spring.beans.TextEditor" autowire="constructor">
bean>
<bean id="spellChecker" class="com.marcus.spring.beans.SpellChecker">
<property name="wordsList">
<list>
<value>textvalue>
<value>woodvalue>
<value>supermanvalue>
list>
property>
bean>
<bean id="spellChecker2" class="com.marcus.spring.beans.SpellChecker" autowire-candidate="false">
<property name="wordsList">
<list>
<value>textvalue>
<value>woodvalue>
<value>supermanvalue>
list>
property>
bean>
beans>
package com.marcus.spring.beans;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DIAutoByApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di-autoby.xml");
TextEditor textEditor = context.getBean("textEditor", TextEditor.class);
System.out.println("textEditor->generateType: " + textEditor.getGenerateType());
System.out.println("textEditor->checkText: " + textEditor.getText());
System.out.println("textEditor->spellCheck: " + textEditor.spellCheck());
System.out.println("");
TextEditor textEditor2 = context.getBean("textEditor2", TextEditor.class);
System.out.println("textEditor2->generateType: " + textEditor2.getGenerateType());
System.out.println("textEditor2->checkText: " + textEditor2.getText());
System.out.println("textEditor2->spellCheck: " + textEditor2.spellCheck());
System.out.println("");
TextEditor textEditor3 = context.getBean("textEditor3", TextEditor.class);
System.out.println("textEditor3->generateType: " + textEditor3.getGenerateType());
System.out.println("textEditor3->checkText: " + textEditor3.getText());
System.out.println("textEditor3->spellCheck: " + textEditor3.spellCheck());
context.close();
}
}
textEditor->generateType: autoWire = byName
textEditor->checkText: Text, Wood, SuperMen
textEditor->spellCheck: SuperMen spells error!
textEditor2->generateType: autoWire = byType
textEditor2->checkText: Text, Wood, SuperMen, byType
textEditor2->spellCheck: SuperMen,byType spells error!
textEditor3->generateType: autoWire = constructor
textEditor3->checkText: Text, Wood, SuperMen, byType
textEditor3->spellCheck: SuperMen,byType spells error!
这种模式由属性名称指定自动装配。例如上文的textEditor,其定义设置为自动装配 byName,并且它包含 spellChecker 属性(即,它有一个 setSpellChecker(…) 方法),那么 Spring 就会查找定义名为 spellChecker 的 bean,并且用它来设置这个属性。你仍然可以使用
这种模式由属性类型指定自动装配。例如上文的textEditor2,在定义设置为自动装配 byType,并且它包含 SpellChecker 类型的 spellChecker 属性,那么 Spring 就会查找定义类型为 SpellChecker 的 bean,并且用它来设置这个属性。
如果存在多个类型一样的bean,如上文的spellChecker,spellChecker2,如果没有特殊处理,则spring ioc容器在bean实例化时就会报错,不知道该注入spellChecker还是spellChecker2。这时,我们需要设置spellChecker2的autowire-candidate=“false”,则表示spellChecker2不参与依赖注入,所以spring容器会将spellChecker注入到textEditor。
这种模式与 byType 非常相似,但它应用于构造器参数。在 XML 配置文件中 bean的 autowire 属性设置为 constructor。然后,spring尝试把构造函数的参数与配置文件中 beans 类型进行匹配,如果找到匹配项,它会注入这些 bean。如上文的textEditor3,构造函数有个参数类型为SpellChecker,Spring 会查找定义类型SpellChecker 的 bean,并用它来设置构造函数的参数。
从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 定义,你可以使用相关类,方法或字段声明的注解,将 bean 配置移到bean类本身。这里介绍3个重要的注解:@Required,@Autowired,@Qualifier。
使用注解时必须启动注解驱动
一个案例,如下:
package com.marcus.spring.beans;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
@Autowired
@Qualifier("student1")
private Student student;
public Profile() {
System.out.println("Inside Profile constructor.");
}
public void setStudent(Student student) {
this.student = student;
}
public void printInfo() {
System.out.println("Student-Name: " + student.getName());
System.out.println("Student-Age: " + student.getAge());
}
}
package com.marcus.spring.beans;
import org.springframework.beans.factory.annotation.Required;
public class Student {
private Integer age;
private String name;
@Required
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="student1" class="com.marcus.spring.beans.Student">
<property name="name" value="Zara" />
<property name="age" value="11" />
bean>
<bean id="student2" class="com.marcus.spring.beans.Student">
<property name="name" value="Student2" />
<property name="age" value="22" />
bean>
<bean id="profile" class="com.marcus.spring.beans.Profile" />
<bean id="profile2" class="com.marcus.spring.beans.Profile">
<property name="student" ref="student2" />
bean>
beans>
package com.marcus.spring.beans;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DIAnnotationApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di-annotation.xml");
Profile profile = context.getBean("profile", Profile.class);
profile.printInfo();
System.out.println("");
Profile profile2 = context.getBean("profile2", Profile.class);
profile2.printInfo();
System.out.println("");
context.close();
//输出结果
//Student-Name: Zara
//Student-Age: 11
//Student-Name: Student2
//Student-Age: 22
}
}
@Required 注解应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器会抛出一个 BeanInitializationException 异常。如上文的Student,其age和name都设为@Required,则xml配置文件中,必须指定:
否则spring容器初始化时会报BeanInitializationException异常。
@Autowired 自动装配更灵活,控制的更细微。
@Autowired 注解可以在 setter 方法、field和构造函数中使用。
@Autowired 的(required=false)选项,默认情况下,@Autowired 注解意味着依赖是必须的,它类似于 @Required 注释,然而,你可以使用 @Autowired 的 (required=false) 选项关闭默认行为。
无需setter方法。
public class Profile {
@Autowired
@Qualifier("student1")
private Student student;
public Profile() {
System.out.println("Inside Profile constructor.");
}
public void printInfo() {
System.out.println("Student-Name: " + student.getName());
System.out.println("Student-Age: " + student.getAge());
}
}
public class Profile2 {
private Student student;
public Profile2() {
System.out.println("Inside Profile2 constructor.");
}
@Autowired
@Qualifier("student2")
public void setStudent(Student student) {
this.student = student;
}
public void printInfo() {
System.out.println("Student-Name: " + student.getName());
System.out.println("Student-Age: " + student.getAge());
}
}
构造函数中的@Autowired,不能使用@Qualifier,这时Profile如果要注入student问题就来了,上文我们注册了2个student bean,这时spring ioc容器就懵了,不知道引用哪个student bean,导致spring ioc容器初始化时会报错。
在根据类型不能成功匹配时,我们只好使用byName,通过构造函数的参数名称与xml配置文件中的bean id匹配实现student bean注入。如本案例构造函数参数名称为student3,xml配置文件中定义了一个id为student3的bean,因此spring容器启动时会找到student3并注入到profile3。
package com.marcus.spring.beans;
import org.springframework.beans.factory.annotation.Autowired;
public class Profile3 {
private Student student;
@Autowired
public Profile3(Student student3) {
System.out.println("Inside Profile3 constructor.");
this.student = student3;
}
public void printInfo() {
System.out.println("Student-Name: " + student.getName());
System.out.println("Student-Age: " + student.getAge());
}
}
<bean id="student1" class="com.marcus.spring.beans.Student">
<property name="name" value="Zara" />
<property name="age" value="11" />
bean>
<bean id="student2" class="com.marcus.spring.beans.Student">
<property name="name" value="Student2" />
<property name="age" value="22" />
bean>
<bean id="student3" class="com.marcus.spring.beans.Student">
<property name="name" value="Student3" />
<property name="age" value="33" />
bean>
<bean id="profile" class="com.marcus.spring.beans.Profile" />
<bean id="profile2" class="com.marcus.spring.beans.Profile2" />
<bean id="profile3" class="com.marcus.spring.beans.Profile3" />
spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
public class Profile4 {
@Resource(name="student1")
private Student student;
public Profile4() {
System.out.println("Inside Profile4 constructor.");
}
public void printInfo() {
System.out.println("Student-Name: " + student.getName());
System.out.println("Student-Age: " + student.getAge());
}
}
xml配置片段
<bean id="profile4" class="com.marcus.spring.beans.Profile4" />