target
掌握依賴注入的三種方式
掌握基于xml的bean裝配
掌握基于注解的bean裝配
掌握bean的自動裝配
掌握注解 @Autowired 和 @Resource
1. 依賴注入
當一個bean創(chuàng)建出來后乡翅,是一個空對象女蜈,需要給bean進行賦值哼蛆,這個bean才有意義兆龙。依賴注入就是給IoC中的bean進行賦值,一般可以分為三種。
1.1 set注入
以前的開發(fā)中,當創(chuàng)建完bean對象后,一般會使用set方法給對象進行賦值鹉梨。
set注入,顧名思義就是用實體類的setter方法進行注入穿稳。
set注入是用的是最多的注入方式存皂。
注入用的標簽是property。
??新建 Java項目Spring-02
逢艘,給Teacher和Course進行注入:
第一步:在src下新建實體類:
Teacher.java:
package com.lee.spring.bean;
public class Teacher {
private int no;//工號
private String name;//姓名
// getter旦袋、setter、toString略
}
Course.java
package com.lee.spring.bean;
public class Course {
private String courseName;//課程名字
private int courseHours;//課時量
private Teacher courseTeacher;//授課老師
/ / getter它改、setter疤孕、toString略
}
第二步:在src下新建配置文件 applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.spring.bean.Course">
<property name="courseName" value="語文"></property>
<property name="courseHours" value="200"></property>
<property name="courseTeacher" ref="teacher"></property>
</bean>
</beans>
注意:
在賦值的時候,如果是簡單類型(8個基本類型 + String)央拖,用value賦值祭阀。如果是對象類型,用ref(ref是reference的簡寫鲜戒,引用的意思)专控。
第三步:編寫一個測試類進行測試:
package com.lee.spring.test;
public class TestDemo {
@Test
public void test01() {
//獲取上下文對象:Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean對象
Course course = (Course)context.getBean("course");
System.out.println(course);
}
}
輸出:
Course [courseName=語文, courseHours=200, courseTeacher=Teacher [no=1001, name=張三]]
原理解釋:
setter注入用到了實體類的setter方法,和getter方法遏餐、構(gòu)造方法都沒關(guān)系伦腐。我們可以在setter方法里面加一行輸出語句驗證。
set注入底層用的是反射技術(shù)失都,bean標簽里的class是全類名柏蘑,所以可以用Class.forName("全類名")拿到這個類的所有信息,然后用new Instance方法創(chuàng)建一個對象粹庞,getmethod()方法拿到所有的set方法咳焚,在調(diào)用setter方法將值注入。
Class clz = Class.forName("全類名");
Object obj = clz.newInstance();//創(chuàng)建對象
Method method = clz.getMethod("set方法名字");//獲取setter方法
method.invoke(obj, value里面的值);//調(diào)用setter方法賦值
1.2 構(gòu)造器注入
對象的創(chuàng)建信粮,使用的是構(gòu)造方法黔攒。
構(gòu)造器注入用的是實體類的構(gòu)造方法趁啸。
注入用的標簽是constructor-arg
第一步:在src下新建實體類强缘,并且生成構(gòu)造方法
Teacher.java
package com.lee.spring.bean;
public class Teacher {
private int no;//工號
private String name;//姓名
public Teacher(int no, String name) {
this.no = no;
this.name = name;
}
public Teacher() {
}
@Override
public String toString() {
return "Teacher [no=" + no + ", name=" + name + "]";
}
}
Course.java
package com.lee.spring.bean;
public class Course {
private String courseName;//課程名字
private int courseHours;//課時量
private Teacher courseTeacher;//授課老師
public Course(String courseName, int courseHours, Teacher courseTeacher) {
this.courseName = courseName;
this.courseHours = courseHours;
this.courseTeacher = courseTeacher;
}
public Course() {
}
@Override
public String toString() {
return "Course [courseName=" + courseName + ", courseHours=" + courseHours + ", courseTeacher=" + courseTeacher
+ "]";
}
}
第二步:在 src下新建配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="no" value="2002"></constructor-arg>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.spring.bean.Course">
<constructor-arg name="courseName" value="數(shù)學(xué)"></constructor-arg>
<constructor-arg name="courseHours" value="300"></constructor-arg>
<constructor-arg name="courseTeacher" ref="teacher"></constructor-arg>
</bean>
</beans>
第三步:編寫一個測試類督惰,進行測試
package com.lee.spring.test;
public class TestDemo {
@Test
public void test02() {
//獲取上下文對象:Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean對象
Course course = (Course)context.getBean("course");
System.out.println(course);
}
}
輸出:Course [courseName=數(shù)學(xué), courseHours=300, courseTeacher=Teacher [no=2002, name=李四]]
補充:配置文件還可以這樣寫
- 省略name:但是順序要和構(gòu)造方法中參數(shù)的順序一致
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.entity.Teacher">
<constructor-arg value="2002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course">
<constructor-arg value="數(shù)學(xué)"></constructor-arg>
<constructor-arg value="300"></constructor-arg>
<constructor-arg ref="teacher"></constructor-arg>
</bean>
- 用index:下標要從0開始
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.entity.Teacher">
<constructor-arg index="0" value="2002"></constructor-arg>
<constructor-arg index="1" value="李四"></constructor-arg>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course">
<constructor-arg index="0" value="數(shù)學(xué)"></constructor-arg>
<constructor-arg index="1" value="300"></constructor-arg>
<constructor-arg index="2" ref="teacher"></constructor-arg>
</bean>
原理解釋:
構(gòu)造器注入用到了實體類的構(gòu)造方法。我們可以在構(gòu)造方法里面加一行輸出語句驗證旅掂。
構(gòu)造器注入底層用的也是反射技術(shù)赏胚,bean標簽里的class是全類名,所以可以用Class.forName("全類名")拿到這個類的所有信息商虐,然后用getConstructor()方法獲取構(gòu)造器觉阅,調(diào)用newInstance()方法就可以創(chuàng)造出對象。
Class clz = Class.forName("全類名");
Constructor constructor = clz.getConstructor(int.class,String.class);
Object instance = constructor.newInstance("value里面的值");
1.3 p命名空間注入
首先需要引入p命名空間秘车,在namespaces里將p勾上典勇。然后在bean標簽里面寫就行了,注意中間要加上空格叮趴。此時直接編寫配置文件是沒有提示的割笙,當在實體類中加上setter方法,就有提示了眯亦,所以p命名空間本質(zhì)上也是用的setter注入
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.entity.Teacher" p:name="王五" p:no="3003"></bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course" p:courseName="hadoop" p:courseHours="280" p:courseTeacher-ref="teacher"></bean>
</beans>
注意:
沒有
-ref
就是簡單注入伤溉,p:courseName="hadoop"
有-ref
就是對象注入,p:courseTeacher-ref="teacher"
多個屬性賦值時妻率,中間要加空格
三種注入方式乱顾,我們絕大多數(shù)用set注入。
2. bean裝配概述
bean的裝配其實做的只有兩件事:為bean賦值宫静、組合bean之間的關(guān)系走净。
在 Spring 中提供了 3 種方法進行裝配:
基于xml配置裝配bean
基于注解裝配bean
自動裝配
在現(xiàn)實的工作中,這 3 種方式都會被用到囊嘉,并且在學(xué)習(xí)和工作之中常澄录迹混合使用,所以這里給出一些關(guān)于這 3 種優(yōu)先級的建議:
① 最優(yōu)先:自動裝配
基于約定優(yōu)于配置的原則扭粱,這種方式應(yīng)該是最優(yōu)先的
好處:減少程序開發(fā)者的決定權(quán)舵鳞,簡單又不失靈活。
② 其次:基于注解裝配bean
在沒有辦法使用自動裝配原則的情況下應(yīng)該優(yōu)先考慮此類方法
好處:避免 XML 配置的泛濫琢蛤,也更為容易蜓堕。
典型場景:一個父類有多個子類,比如學(xué)生類有兩個子類博其,一個男學(xué)生類和女學(xué)生類套才,通過 IoC 容器初始化一個學(xué)生類,容器將無法知道使用哪個子類去初始化慕淡,這個時候可以使用 Java 的注解配置去指定背伴。
③ 最后:XML 方式配置
在上述方法都無法使用的情況下,那么也只能選擇 XML 配置的方式。
好處:簡單易懂
通俗來講傻寂,現(xiàn)在開發(fā)中息尺,優(yōu)先考慮 注解裝配 + 自動裝配。老項目的維護疾掰,可以考慮使用 xml方式 裝配搂誉。
3. 基于xml的裝配
前面所講到的裝配都是基于xml方式的裝配,因為基于xml的裝配更容易理解静檬。
3.1 簡單裝配
簡單裝配就是給一個8個基本數(shù)據(jù)類型+String的屬性賦值炭懊,比如:
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
3.2 集合屬性裝配
對于一些集合屬性的賦值,比如list集合拂檩、set集合侮腹、map集合、數(shù)組稻励、Properties等凯旋,我們可以這樣來賦值:
第一步:新建實體類
public class CollectionInject {
private List<String> listElement;
private Set<String> setElement;
private String[] strElement;
private Map<String,String> mapElement;
private Properties propElement;
//getter、setter省略
@Override
public String toString() {
return "listElement=" + listElement + "\nsetElement=" + setElement + "\nstrElement="
+ Arrays.toString(strElement) + "\nmapElement=" + mapElement + "\npropElement=" + propElement ;
}
}
第二步:在 src新建配置文件 applicationContext.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 將集合注入到IOC容器 -->
<bean id="coll" class="com.lee.spring.bean.CollectionInject">
<!-- list集合注入 -->
<property name="listElement" >
<list>
<value>足球</value>
<value>籃球</value>
<value>乒乓球</value>
</list>
</property>
<!-- set集合注入 -->
<property name="setElement">
<set>
<value>語文</value>
<value>數(shù)學(xué)</value>
<value>英語</value>
</set>
</property>
<!-- 數(shù)組集合注入 -->
<property name="strElement">
<array>
<value>手機</value>
<value>電腦</value>
<value>平板</value>
</array>
</property>
<!-- map集合注入 -->
<property name="mapElement">
<map>
<entry>
<key>
<value>shoes</value>
</key>
<value>鞋子</value>
</entry>
<entry>
<key>
<value>cap</value>
</key>
<value>帽子</value>
</entry>
<entry>
<key>
<value>coat</value>
</key>
<value>外套</value>
</entry>
</map>
</property>
<!-- property注入 -->
<property name="propElement">
<props>
<prop key="bread">面包</prop>
<prop key="chocolate">巧克力</prop>
<prop key="milk">牛奶</prop>
</props>
</property>
</bean>
</beans>
記憶技巧:除了properties钉迷,所有的集合賦值都在value標簽里進行至非。
第三步:在測試類中測試
@Test
public void test04() {
//獲取上下文對象:Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean對象
CollectionInject coll = (CollectionInject)context.getBean("coll");
System.out.println(coll);
}
輸出:
listElement=[足球, 籃球, 乒乓球]
setElement=[語文, 數(shù)學(xué), 英語]
strElement=[手機, 電腦, 平板]
mapElement={shoes=鞋子, cap=帽子, coat=外套}
propElement={bread=面包, chocolate=巧克力, milk=牛奶}
注意:
其中l(wèi)ist、set糠聪、array可以混合使用
也可以用構(gòu)造器賦值,和set注入一樣荒椭,就是換個標簽而已
<constructor-arg name="listElement" >
<list>
<value>足球</value>
<value>籃球</value>
<value>乒乓球</value>
</list>
</constructor-arg>
3.3 特殊值裝配
如果我們想注入一些特殊值:>、<舰蟆、&等趣惠,可以考慮<value>
標簽。
value和<value>
注入的區(qū)別:
<value>標簽 | value屬性 | |
---|---|---|
參數(shù)位置 | 寫在首尾標簽(<value></value>)的中間身害,不加雙引號 | 寫在value的屬性值中味悄,必須加雙引號 |
參數(shù)值包含特殊符號 | 方式一:使用<![CDATA[]]>標記 方式二:使用xml預(yù)定義的實體引用 |
使用xml預(yù)定義的實體引用 |
參數(shù)值帶雙引號輸出 | 可以 | 不可以 |
其中,xml預(yù)定義實體引用:
實體引用 | 符號 |
---|---|
> | > |
< | < |
& | & |
注意有分號塌鸯。
① 字符串
配置文件:
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" value="王五"></property>
<property name="no" value="5005"></property>
</bean>
測試:
@Test
public void test05() {
//獲取上下文對象:Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean對象
Teacher teacher = (Teacher)context.getBean("teacher");
System.out.println(teacher);
}
輸出:[no=5005, name=王五]
還可以使用<value>
寫:
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" ><value>王五</value></property>
<property name="no" ><value>5005</value></property>
</bean>
我們?nèi)绻胼敵觯篬no=5005, name="王五"]侍瑟,就必須用<value>
標簽:
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher2" class="com.lee.spring.bean.Teacher">
<property name="name" ><value>"王五"</value></property>
<property name="no" ><value>5005</value></property>
</bean>
② 特殊字符
a. 使用<value>標簽
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name">
<value><![CDATA[<&>]]></value>
</property>
<property name="no" value="1001"></property>
</bean>
或者
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name">
<value>><&</value>
</property>
<property name="no" value="1001"></property>
</bean>
b. 使用value屬性
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" value="><&"></property>
<property name="no" value="1001"></property>
</bean>
開發(fā)中絕大多數(shù)使用value屬性的方式注入
③ 賦空值
a. 空字符串""
裝配空字符串有兩種方式:
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" value=""></property>
</bean>
或者
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" ><value></value></property>
</bean>
b. null
null表示該對象是空的,只能這樣做:用<null>標簽
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name"> <null/></property>
</bean>
注意:不能用下面方法做
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<property name="name" value="null"></property>
</bean>
這樣表示這個人的名字叫null丙猬,而不是空涨颜。
4. 基于注解的裝配
基于注解的裝配就是不使用xml配置文件,使用注解來進行裝配茧球。
??用三層結(jié)構(gòu)中的Service層來模擬一下注解裝配庭瑰。
用配置文件的方法需要這樣做:
StudentService.java
package com.lee.spring.service;
public class StudentService {
public void addStudent() {
System.out.println("增加學(xué)生。抢埋。弹灭。");
}
}
applicationContext.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="studentService" class="com.lee.spring.service.StudentService"></bean>
</beans>
此時督暂,StudentService類就已經(jīng)納入到IOC容器中了,可以通過eclipse左邊StudentService類旁邊的S來確定是不是納入成功穷吮。
4.1 用注解裝配步驟
首先需要在配置文件中打開包掃描功能:
<?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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--開啟包掃描-->
<context:component-scan base-package="com.lee.spring.service"></context:component-scan>
</beans>
然后在StudentService類頭上加相關(guān)注解即可:
package com.lee.spring.service;
import org.springframework.stereotype.Component;
@Component("studentService")
public class StudentService {
public void addStudent() {
System.out.println("增加學(xué)生损痰。。酒来。");
}
}
說明
第一點:
@Component("studentService")
就等價于<bean id="studentService" class="com.lee.spring.service.StudentService"></bean>
注解括號里面的值就是bean的id值。
第二點:
在Spring啟動的時候肪凛,會根據(jù)<context:component-scan base-package="com.lee.spring.service"></context:component-scan>
中的base-package去掃描這個包下的所有類堰汉,如果發(fā)現(xiàn)該包下有哪個類存在組件相關(guān)的注解,就將他納入到IOC容器中伟墙。
4.2 其他注解
開發(fā)中會用到下面四個注解:
@Component:可以在三層中的任何一層中使用翘鸭,還有一些功能性的bean使用。
@Controller:控制器層使用戳葵。
@Service:service層使用就乓。
@Repository:dao層使用。
下面演示一個用@Component注解給普通的bean賦值:
第一步:直接在實體類上標注 @Component("p") 注解拱烁,p是bean的名字生蚁。
第二步:用@Value("小花")注解直接在屬性上賦值,不需要getter戏自、setter方法邦投。
- 實體類 Person.java:
@Component("p")
public class Person {
@Value("1001")
private int id;
@Value("小花")
private String name;
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}
- 配置文件 applicationContext.xml :
<?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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--開啟包掃描-->
<context:component-scan base-package="com.lee.spring.bean"></context:component-scan>
</beans>
- 測試
@Test
public void test08() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person p = (Person)context.getBean("p");
System.out.println(p);
}
輸出:Person [id=1001, name=小花]
5. 自動裝配
開發(fā)中有一個原則:約定優(yōu)于配置。所以能夠按照約定自動去裝配的盡量自動裝配擅笔。
但是需要注意:自動裝配僅適用于對象類型志衣,對于簡單類型不適用。
自動裝配分為兩種猛们,一種是基于xml方式的自動裝配念脯,一種是基于注解方式的自動裝配⊥涮裕基于注解方式的自動裝配是比較常用的绿店。
5.1 基于xml的自動裝配
自動裝配分為三種,分別是 通過名字裝配庐橙、通過類型裝配惯吕、使用構(gòu)造器裝配。
① byName
- 新建實體類:
Teacher.java
public class Teacher {
private int no;
private String teaName;
//getter怕午、setter省略
@Override
public String toString() {
return "Teacher [no=" + no + ", teaName=" + teaName + "]";
}
}
Course.java
public class Course {
private String courseName;//課程名字
private int courseHours;//課時量
private Teacher courseTeacher;//授課老師
//getter废登、setter省略
@Override
public String toString() {
return "[課程名字:" + courseName + ", 課時量:" + courseHours + ", 老師信息:" + courseTeacher + "]";
}
}
- 編寫配置文件applicationContext.xml如下:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean id="teacher" class="com.lee.entity.Teacher">
<property name="teaName" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course">
<property name="courseName" value="語文"></property>
<property name="courseHours" value="200"></property>
<property name="courseTeacher" ref="teacher"></property>
</bean>
</beans>
以上的裝配是手工裝配的。
自動裝配就是我不寫<property name="courseTeacher" ref="teacher"></property>
這行代碼郁惜,想辦法讓程序自動在IOC容器中去尋找teacher這個bean堡距,答案是可以的甲锡。刪掉這行代碼,然后在course的標簽中加一句 autowire="byName" 羽戒。
運行程序缤沦,發(fā)現(xiàn)老師信息是null,說明沒有程序沒有找到對應(yīng)的teacher的bean易稠。既然是按照名字自動裝配缸废,所以得保證屬性的名字和bean的名字一致
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean id="courseTeacher" class="com.lee.entity.Teacher">
<property name="teaName" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course" autowire="byName">
<property name="courseName" value="語文"></property>
<property name="courseHours" value="200"></property>
</bean>
</beans>
- 測試
@Test
public void testAutowire() {
//獲取上下文對象:Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean對象
Course course = (Course)context.getBean("course");
System.out.println(course);
}
按照名字裝配,必須保證屬性名和被裝配bean的id名一致驶社。
② byType
byType自然就是按照類型裝配企量。
在被裝配的bean中加入autowire="byType"
:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean class="com.lee.entity.Teacher">
<property name="teaName" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course" autowire="byType">
<property name="courseName" value="語文"></property>
<property name="courseHours" value="200"></property>
</bean>
</beans>
如果IOC容器中有一個bean的類型恰好是該類的引用類型,則可以按照類型自動裝配亡电。
弊端:
如果IOC容器中有兩個類型一樣的bean届巩,則程序不知道該裝配哪一個,就會裝配失敗份乒。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 將老師信息注入到IOC容器 -->
<bean class="com.lee.entity.Teacher">
<property name="teaName" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
<!-- 將老師2信息注入到IOC容器 -->
<bean class="com.lee.entity.Teacher">
<property name="teaName" value="李四"></property>
<property name="no" value="2002"></property>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course" autowire="byType">
<property name="courseName" value="語文"></property>
<property name="courseHours" value="200"></property>
</bean>
</beans>
會拋這樣一個異常:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.lee.entity.Teacher' available: expected single matching bean but found 2: com.lee.entity.Teacher#0,com.lee.entity.Teacher#1
③ constructor
根據(jù)構(gòu)造器去自動裝配恕汇。所以實體類要有構(gòu)造方法。
配置文件: autowire="constructor"
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="teacher" class="com.lee.spring.bean.Teacher">
<constructor-arg name="no" value="1001"></constructor-arg>
<constructor-arg name="name" value="張曉三"></constructor-arg>
</bean>
<bean id="course" class="com.lee.spring.bean.Course" autowire="constructor">
<constructor-arg name="courseName" value="Spring"></constructor-arg>
<constructor-arg name="courseHours" value="100"></constructor-arg>
</bean>
</beans>
注意:同樣IOC容器中不能有兩個teacher類型的bean或辖,否則裝配失敗瘾英,并且拋異常。
全局自動裝配
全局自動裝配使用:default-autowire
可以給每一個類進行自動裝配颂暇,也能給全局bean都設(shè)置自動裝配方咆。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byName"
>
<!-- 將老師信息注入到IOC容器 -->
<bean id ="courseTeacher" class="com.lee.entity.Teacher">
<property name="teaName" value="張三"></property>
<property name="no" value="1001"></property>
</bean>
<!-- 將課程信息注入到IOC容器 -->
<bean id="course" class="com.lee.entity.Course" >
<property name="courseName" value="語文"></property>
<property name="courseHours" value="200"></property>
</bean>
</beans>
注意:
局部bean的自動裝配可以覆蓋全局bean自動裝配。
5.2 基于注解的自動裝配
基于注解的自動裝配有兩種蟀架,分別是 通過類型自動裝配 和 通過名字自動裝配瓣赂。
基于注解的裝配在開發(fā)中是最常用的,一般三層架構(gòu)的裝配都是使用注解自動裝配片拍。
① @Autowired
@Autowired默認根據(jù)類型進行裝配煌集。和 byType是一樣的。
用配置文件方式模擬一個開發(fā)中的三層架構(gòu):
Dao層:
package com.lee.spring.dao;
public interface StudentDao {
void addStudent();
}
package com.lee.spring.dao.impl;
public class StudentDaoImpl implements StudentDao {
@Override
public void addStudent() {
System.out.println("添加學(xué)生...");
}
}
Service層:
package com.lee.spring.service;
public interface StudentService {
void addStudent();
}
package com.lee.spring.service.impl;
public class StudentServiceImpl implements StudentService{
StudentDao studentDao;
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
public void addStudent() {
studentDao.addStudent();
}
}
Controller層:
package com.lee.spring.controller;
public class AddStudentController {
public void setStudentService(StudentService studentService) {
this.studentService = studentService;
}
StudentService studentService;
public void addStudent() {
studentService.addStudent();
}
}
配置文件:
<?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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 將控制器納入到IOC容器 -->
<bean id="addStudentController" class="com.lee.spring.controller.AddStudentController">
<property name="studentService" ref="studentService"></property>
</bean>
<!-- 將studentService納入到IOC容器 -->
<bean id="studentService" class="com.lee.spring.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"></property>
</bean>
<!-- 將studentDao納入到IOC容器 -->
<bean id="studentDao" class="com.lee.spring.dao.impl.StudentDaoImpl"></bean>
</beans>
測試:
@Test
public void test08() {
//獲取上下文對象:Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean對象
AddStudentController addStudentController = (AddStudentController)context.getBean("addStudentController");
addStudentController.addStudent();
}
用注解方式實現(xiàn):
Dao層:
package com.lee.spring.dao;
public interface StudentDao {
void addStudent();
}
package com.lee.spring.dao.impl;
@Repository
public class StudentDaoImpl implements StudentDao {
@Override
public void addStudent() {
System.out.println("添加學(xué)生...");
}
}
Service層:
package com.lee.spring.service;
public interface StudentService {
void addStudent();
}
package com.lee.spring.service.impl;
@Service
public class StudentServiceImpl implements StudentService{
@Autowired
StudentDao studentDao;
@Override
public void addStudent() {
studentDao.addStudent();
}
}
Controller層:
package com.lee.spring.controller;
@Controller
public class AddStudentController {
@Autowired
StudentService studentService;
public void addStudent() {
studentService.addStudent();
}
}
配置文件:
<?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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.lee"></context:component-scan>
</beans>
如果IOC容器沒有StudentDao這個bean捌省,StudentService層源碼是這樣:
package com.lee.spring.service.impl;
@Service
public class StudentServiceImpl implements StudentService{
@Autowired
StudentDao studentDao;
@Override
public void addStudent() {
studentDao.addStudent();
}
}
當容器獲取stuService組件時苫纤,程序會報錯,因為stuService依賴StudentDao纲缓,但是IOC容器還沒有StudentDao卷拘,所以報錯。怎么讓程序不依賴StudentDao:在@AutoWired注解后加:required = false
package com.lee.spring.service.impl;
@Service
public class StudentServiceImpl implements StudentService{
@Autowired(required = false)
StudentDao studentDao;
@Override
public void addStudent() {
studentDao.addStudent();
}
}
② @Qualifier
當一個接口有多個實現(xiàn)類時祝高,需要用@Autowired + @Qualifier組合來區(qū)分到底調(diào)用哪個類的實現(xiàn)栗弟。
@Controller("addStudentController")
public class AddStudentController {
@Autowired
@Qualifier("stuService")
StudentService studentService;
public void addStudent() {
studentService.addStudent();
}
}
其中@Qualifier("stuService")括號中的stuService就是我們之前定義@Service注解的名稱。
注意:@Qualifier必須和@Autowired一起使用才有效工闺。
③ @Resource
@Resource注解是通過byName注入的乍赫。
@Controller("addStudentController")
public class AddStudentController {
@Resource(name = "stuService")
StudentService studentService;
public void addStudent() {
studentService.addStudent();
}
}
④ @Resource和@Autowired區(qū)別
① @Autowired為Spring提供的注解瓣蛀。@Resource并不是Spring的注解,它的包是javax.annotation.Resource
② @Autowired按照byType注入雷厂,@Resource默認按照ByName自動注入惋增。