第1章 Spring 概述
1.1 spring 概述[了解]
1.1.1 spring 是什么
? Spring 是分層的 Java SE/EE 應(yīng)用 full-stack
輕量級(jí)開源框架,以IoC(Inverse Of Control:反轉(zhuǎn)控制)和AOP(Aspect Oriented Programming:面向切面編程)為內(nèi)核
,提供了展現(xiàn)層 SpringMVC 和持久層 Spring JDBC 以及業(yè)務(wù)層事務(wù)管理等眾多的企業(yè)級(jí)應(yīng)用技術(shù),還能整合開源世界眾多著名的第三方框架和類庫,逐漸成為使用最多的 Java EE 企業(yè)應(yīng)用開源框架。
1.1.2 spring 的優(yōu)勢(shì)
方便解耦,簡(jiǎn)化開發(fā)
通過 Spring 提供的 IoC 容器,可以將對(duì)象間的依賴關(guān)系交由 Spring 進(jìn)行控制,避免硬編碼所造成的過度程序耦合。用戶也不必再為單例模式類盛杰、屬性文件解析等這些很底層的需求編寫代碼,可以更專注于上層的應(yīng)用存皂。
AOP 編程的支持
通過 Spring 的 AOP 功能,方便進(jìn)行面向切面的編程,許多不容易用傳統(tǒng) OOP 實(shí)現(xiàn)的功能可以通過 AOP 輕松應(yīng)付晨川。
聲明式事務(wù)的支持
可以將我們從單調(diào)煩悶的事務(wù)管理代碼中解脫出來,通過聲明式方式靈活的進(jìn)行事務(wù)的管理,提高開發(fā)效率和質(zhì)量。
方便程序的測(cè)試
可以用非容器依賴的編程方式進(jìn)行幾乎所有的測(cè)試工作,測(cè)試不再是昂貴的操作,而是隨手可做的事情椭微。
方便集成各種優(yōu)秀框架
? Spring 可以降低各種框架的使用難度,提供了對(duì)各種優(yōu)秀框架(Struts、 Hibernate蝇率、 Hessian、 Quartz等)的直接支持本慕。
降低 JavaEE API 的使用難度
Spring 對(duì) JavaEE API(如 JDBC排拷、JavaMail锅尘、遠(yuǎn)程調(diào)用等)進(jìn)行了薄薄的封裝層,使這些 API 的使用難度大為降低。
Java 源碼是經(jīng)典學(xué)習(xí)范例
Spring 的源代碼設(shè)計(jì)精妙藤违、結(jié)構(gòu)清晰纺弊、匠心獨(dú)用,處處體現(xiàn)著大師對(duì) Java 設(shè)計(jì)模式靈活運(yùn)用以及對(duì) Java 技術(shù)的高深造詣骡男。它的源代碼無意是 Java 技術(shù)的最佳實(shí)踐的范例。
第2章 IoC 的概念和作用
2.1 程序的耦合和解耦[理解]
2.1.1 什么是程序的耦合
? 耦合性(Coupling),也叫耦合度,是對(duì)模塊間關(guān)聯(lián)程度的度量犹菱。耦合的強(qiáng)弱取決于模塊間接口的復(fù)雜性吮炕、調(diào)用模塊的方式以及通過界面?zhèn)魉蛿?shù)據(jù)的多少。模塊間的耦合度是指模塊之間的依賴關(guān)系,包括控制關(guān)系陕凹、調(diào)用關(guān)系鳄炉、數(shù)據(jù)傳遞關(guān)系。模塊間聯(lián)系越多,其耦合性越強(qiáng),同時(shí)表明其獨(dú)立性越差 ( 降低耦合性,可以提高其獨(dú)立性)佑女。耦合性存在于各個(gè)領(lǐng)域,而非軟件設(shè)計(jì)中獨(dú)有的,但是我們只討論軟件工程中的耦合。
? 在軟件工程中,耦合指的就是就是對(duì)象之間的依賴性摸吠。對(duì)象之間的耦合越高,維護(hù)成本越高。因此對(duì)象的設(shè)計(jì)應(yīng)使類和構(gòu)件之間的耦合最小嚎花。軟件設(shè)計(jì)中通常用耦合度和內(nèi)聚度作為衡量模塊獨(dú)立程度的標(biāo)準(zhǔn)寸痢。劃分模塊的一個(gè)準(zhǔn)則就是高內(nèi)聚低耦合
。
它有如下分類:
(1) 內(nèi)容耦合紊选。當(dāng)一個(gè)模塊直接修改或操作另一個(gè)模塊的數(shù)據(jù)時(shí),或一個(gè)模塊不通過正常入口而轉(zhuǎn)入另一個(gè)模塊時(shí),這樣的耦合被稱為內(nèi)容耦合。內(nèi)容耦合是最高程度的耦合,應(yīng)該避免使用之族壳。
(2) 公共耦合趣些。兩個(gè)或兩個(gè)以上的模塊共同引用一個(gè)全局?jǐn)?shù)據(jù)項(xiàng),這種耦合被稱為公共耦合坏平。在具有大量公共耦合的結(jié)構(gòu)中,確定究竟是哪個(gè)模塊給全局變量賦了一個(gè)特定的值是十分困難的。
(3) 外部耦合 令境。一組模塊都訪問同一全局簡(jiǎn)單變量而不是同一全局?jǐn)?shù)據(jù)結(jié)構(gòu),而且不是通過參數(shù)表傳遞該全局變量的信息,則稱之為外部耦合顾瞪。
(4) 控制耦合 陈醒。一個(gè)模塊通過接口向另一個(gè)模塊傳遞一個(gè)控制信號(hào),接受信號(hào)的模塊根據(jù)信號(hào)值而進(jìn)行適當(dāng)?shù)膭?dòng)作,這種耦合被稱為控制耦合。
(5) 標(biāo)記耦合 弥鹦。若一個(gè)模塊 A 通過接口向兩個(gè)模塊 B 和 C 傳遞一個(gè)公共參數(shù),那么稱模塊 B 和 C 之間存在一個(gè)標(biāo)記耦合彬坏。
(6) 數(shù)據(jù)耦合膝晾。模塊之間通過參數(shù)來傳遞數(shù)據(jù),那么被稱為數(shù)據(jù)耦合玷犹。數(shù)據(jù)耦合是最低的一種耦合形式,系統(tǒng)中一般都存在這種類型的耦合,因?yàn)闉榱送瓿梢恍┯幸饬x的功能,往往需要將某些模塊的輸出數(shù)據(jù)作為另一些模塊的輸入數(shù)據(jù)洒疚。
(7) 非直接耦合 油湖。兩個(gè)模塊之間沒有直接關(guān)系,它們之間的聯(lián)系完全是通過主模塊的控制和調(diào)用來實(shí)現(xiàn)的领跛。
總結(jié):
耦合是影響軟件復(fù)雜程度和設(shè)計(jì)質(zhì)量的一個(gè)重要因素,在設(shè)計(jì)上我們應(yīng)采用以下原則:如果模塊間必須存在耦合,就盡量使用數(shù)據(jù)耦合,少用控制耦合,限制公共耦合的范圍,盡量避免使用內(nèi)容耦合吠昭。
內(nèi)聚與耦合
內(nèi)聚標(biāo)志一個(gè)模塊內(nèi)各個(gè)元素彼此結(jié)合的緊密程度,它是信息隱蔽和局部化概念的自然擴(kuò)展。內(nèi)聚是從功能角度來度量模塊內(nèi)的聯(lián)系,一個(gè)好的內(nèi)聚模塊應(yīng)當(dāng)恰好做一件事郑什。它描述的是模塊內(nèi)的功能聯(lián)系蒲肋。耦合是軟件結(jié)構(gòu)中各模塊之間相互連接的一種度量,耦合強(qiáng)弱取決于模塊間接口的復(fù)雜程度兜粘、進(jìn)入或訪問一個(gè)模塊的點(diǎn)以及通過接口的數(shù)據(jù)。 程序講究的是低耦合,高內(nèi)聚剃法。就是同一個(gè)模塊內(nèi)的各個(gè)元素之間要高度緊密,但是各個(gè)模塊之間的相互依存度卻要不那么緊密贷洲。
內(nèi)聚和耦合是密切相關(guān)的,同其他模塊存在高耦合的模塊意味著低內(nèi)聚,而高內(nèi)聚的模塊意味著該模塊同其他模塊之間是低耦合悍引。在進(jìn)行軟件設(shè)計(jì)時(shí),應(yīng)力爭(zhēng)做到高內(nèi)聚,低耦合趣斤。
我們?cè)陂_發(fā)中,有些依賴關(guān)系是必須的,有些依賴關(guān)系可以通過優(yōu)化代碼來解除的黎休。
請(qǐng)看下面的示例代碼:
/**
* 賬戶的業(yè)務(wù)層實(shí)現(xiàn)類
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();
}
上面的代碼表示:
業(yè)務(wù)層調(diào)用持久層,并且此時(shí)業(yè)務(wù)層在依賴持久層的接口和實(shí)現(xiàn)類势腮。如果此時(shí)沒有持久層實(shí)現(xiàn)類,編譯將不能通過。這種編譯期依賴關(guān)系,應(yīng)該在我們開發(fā)中杜絕泪幌。我們需要優(yōu)化代碼解決祸泪。
再比如:
早期我們的 JDBC 操作,注冊(cè)驅(qū)動(dòng)時(shí),我們?yōu)槭裁床皇褂?DriverManager 的 register 方法,而是采用Class.forName 的方式?
public class JdbcDemo1 {
/**
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1.注冊(cè)驅(qū)動(dòng)
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.獲取連接
//3.獲取預(yù)處理 sql 語句對(duì)象
//4.獲取結(jié)果集
//5.遍歷結(jié)果集
}
}
原因就是:
我們的類依賴了數(shù)據(jù)庫的具體驅(qū)動(dòng)類(MySQL),如果這時(shí)候更換了數(shù)據(jù)庫品牌(比如 Oracle),需要修改源碼來重新數(shù)據(jù)庫驅(qū)動(dòng)。這顯然不是我們想要的懂扼。
2.1.2 解決程序耦合的思路
當(dāng)是我們講解 jdbc 時(shí),是通過反射來注冊(cè)驅(qū)動(dòng)的,代碼如下:
Class.forName("com.mysql.jdbc.Driver");//此處只是一個(gè)字符串
此時(shí)的好處是,我們的類中不再依賴具體的驅(qū)動(dòng)類,此時(shí)就算刪除 mysql 的驅(qū)動(dòng) jar 包,依然可以編譯(運(yùn)行就不要想了,沒有驅(qū)動(dòng)不可能運(yùn)行成功的)阀湿。
同時(shí),也產(chǎn)生了一個(gè)新的問題,mysql 驅(qū)動(dòng)的全限定類名字符串是在 java 類中寫死的,一旦要改還是要修改源碼瑰妄。
解決這個(gè)問題也很簡(jiǎn)單,使用配置文件配置间坐。
2.1.3 工廠模式解耦
? 在實(shí)際開發(fā)中我們可以把三層的對(duì)象都使用配置文件配置起來,當(dāng)啟動(dòng)服務(wù)器應(yīng)用加載的時(shí)候,讓一個(gè)類中的方法通過讀取配置文件,把這些對(duì)象創(chuàng)建出來并存起來。在接下來的使用的時(shí)候,直接拿過來用就好了涨醋。
那么,這個(gè)讀取配置文件,創(chuàng)建和獲取三層對(duì)象的類就是工廠逝撬。
2.1.4 控制反轉(zhuǎn)-Inversion Of Control
上一小節(jié)解耦的思路有 2 個(gè)問題:
1宪潮、存哪去?
分析:由于我們是很多對(duì)象,肯定要找個(gè)集合來存狡相。這時(shí)候有 Map 和 List 供選擇。
到底選 Map 還是 List 就看我們有沒有查找需求喳挑。有查找需求,選 Map滔悉。
所以我們的答案就是
在應(yīng)用加載時(shí),創(chuàng)建一個(gè) Map,用于存放三層對(duì)象回官。
我們把這個(gè) map 稱之為容器。
2笛坦、還是沒解釋什么是工廠?
工廠就是負(fù)責(zé)給我們從容器中獲取指定對(duì)象的類。這時(shí)候我們獲取對(duì)象的方式發(fā)生了改變蜗帜。
原來:
我們?cè)讷@取對(duì)象時(shí),都是采用 new 的方式厅缺。是主動(dòng)的宴偿。
現(xiàn)在:
我們獲取對(duì)象時(shí),同時(shí)跟工廠要,有工廠為我們查找或者創(chuàng)建對(duì)象窄刘。是被動(dòng)的。
? 這種被動(dòng)接收的方式獲取對(duì)象的思想就是控制反轉(zhuǎn),它是 spring 框架的核心之一。
明確 ioc 的作用:
削減計(jì)算機(jī)程序的耦合(解除我們代碼中的依賴關(guān)系)翻伺。
第3章 使用 spring 的 IOC 解決程序耦合
3.1 案例的前期準(zhǔn)備[會(huì)用]
? 本章我們使用的案例是,賬戶的業(yè)務(wù)層和持久層的依賴關(guān)系解決吨岭。在開始 spring 的配置之前,我們要先準(zhǔn)備一下環(huán)境辣辫。由于我們是使用 spring 解決依賴關(guān)系,并不是真正的要做增刪改查操作,所以此時(shí)我們沒必要寫實(shí)體類。并且我們?cè)诖颂幨褂玫氖?java 工程,不是 java web 工程姐浮。
3.1.1 準(zhǔn)備 spring 的開發(fā)包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
3.1.2 創(chuàng)建業(yè)務(wù)層接口和實(shí)現(xiàn)類
/**
* 賬戶的業(yè)務(wù)層接口
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
*/
public interface IAccountService {
/**
* 保存賬戶(此處只是模擬,并不是真的要保存)
*/
void saveAccount();
}
/**
* 賬戶的業(yè)務(wù)層實(shí)現(xiàn)類
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();//此處的依賴關(guān)系有待解決
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
3.1.3 創(chuàng)建持久層接口和實(shí)現(xiàn)類
/**
* 賬戶的持久層接口
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
*/
public interface IAccountDao {
/**
* 保存賬戶
*/
void saveAccount();
}
/**
* 賬戶的持久層實(shí)現(xiàn)類
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class AccountDaoImpl implements IAccountDao {
@Override
public void saveAccount() {
System.out.println("保存了賬戶");
}
}
3.2 基于 XML 的配置(入門案例)[掌握]
3.2.1 第一步:拷貝必備的 jar 包到工程的 lib 目錄中
3.2.2 第二步:在類的根路徑下創(chuàng)建一個(gè)任意名稱的 xml 文件(不能是中文)
給配置文件導(dǎo)入約束:
/spring-framework-5.0.2.RELEASE/docs/spring-framework-reference/html5/core.html
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3.2.3 第三步:讓 spring 管理資源,在配置文件中配置 service 和 dao
<!-- bean 標(biāo)簽:用于配置讓 spring 創(chuàng)建對(duì)象,并且存入 ioc 容器之中
id 屬性:對(duì)象的唯一標(biāo)識(shí)。
class 屬性:指定要?jiǎng)?chuàng)建對(duì)象的全限定類名
-->
<!-- 配置 service -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
</bean>
<!-- 配置 dao -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
3.2.4 測(cè)試配置是否成功
/**
* 模擬一個(gè)表現(xiàn)層
* @author 黑馬程序員
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class Client {
/**
* 使用 main 方法獲取容器測(cè)試執(zhí)行
*/
public static void main(String[] args) {
//1.使用 ApplicationContext 接口,就是在獲取 spring 容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.根據(jù) bean 的 id 獲取對(duì)象
IAccountService aService = (IAccountService) ac.getBean("accountService");
System.out.println(aService);
IAccountDao aDao = (IAccountDao) ac.getBean("accountDao");
System.out.println(aDao);
}
}
3.3 Spring 基于 XML 的 IOC 細(xì)節(jié)[掌握]
3.3.1 spring 中工廠的類結(jié)構(gòu)圖
3.3.1.1 BeanFactory 和 ApplicationContext
的區(qū)別
BeanFactory
才是 Spring 容器中的頂層接口扫尖。
ApplicationContext
是它的子接口。
BeanFactory
和 ApplicationContext
的區(qū)別:
創(chuàng)建對(duì)象的時(shí)間點(diǎn)不一樣蟀瞧。
ApplicationContext`:只要一讀取配置文件,默認(rèn)情況下就會(huì)創(chuàng)建對(duì)象。
BeanFactory`:什么使用什么時(shí)候創(chuàng)建對(duì)象铸屉。
3.3.1.2 ApplicationContext 接口的實(shí)現(xiàn)類
ClassPathXmlApplicationContext
:
它是從類的根路徑下加載配置文件 推薦使用這種
FileSystemXmlApplicationContext
:
它是從磁盤路徑上加載配置文件,配置文件可以在磁盤的任意位置切端。
AnnotationConfigApplicationContext
:
當(dāng)我們使用注解配置容器對(duì)象時(shí),需要使用此類來創(chuàng)建 spring 容器踏枣。它用來讀取注解。
3.3.2 IOC 中 bean 標(biāo)簽和管理對(duì)象細(xì)節(jié)
3.3.2.1 bean 標(biāo)簽
作用:
用于配置對(duì)象讓 spring 來創(chuàng)建的间驮。
默認(rèn)情況下它調(diào)用的是類中的無參構(gòu)造函數(shù)竞帽。如果沒有無參構(gòu)造函數(shù)則不能創(chuàng)建成功鸿捧。
屬性:
??id
:給對(duì)象在容器中提供一個(gè)唯一標(biāo)識(shí)。用于獲取對(duì)象抱虐。
??class
:指定類的全限定類名恳邀。用于反射創(chuàng)建對(duì)象灶轰。默認(rèn)情況下調(diào)用無參構(gòu)造函數(shù)笋颤。
??scope
:指定對(duì)象的作用范圍。
????singleton
:默認(rèn)值,單例的.
????prototype
:多例的.
????request
:WEB 項(xiàng)目中,Spring 創(chuàng)建一個(gè) Bean 的對(duì)象,將對(duì)象存入到 request 域中.
?????session
:WEB 項(xiàng)目中,Spring 創(chuàng)建一個(gè) Bean 的對(duì)象,將對(duì)象存入到 session 域中.
????global session
:WEB 項(xiàng)目中,應(yīng)用在 Portlet 環(huán)境.如果沒有 Portlet 環(huán)境那么globalSession 相當(dāng)于 session.
??init-method
:指定類中的初始化方法名稱赋除。
??destroy-method
:指定類中銷毀方法名稱非凌。
3.3.2.2 bean 的作用范圍和生命周期
單例對(duì)象:scope="singleton"
一個(gè)應(yīng)用只有一個(gè)對(duì)象的實(shí)例。它的作用范圍就是整個(gè)引用颁糟。
? 生命周期:
對(duì)象出生:當(dāng)應(yīng)用加載,創(chuàng)建容器時(shí),對(duì)象就被創(chuàng)建了。
對(duì)象活著:只要容器在,對(duì)象一直活著玖媚。
對(duì)象死亡:當(dāng)應(yīng)用卸載,銷毀容器時(shí),對(duì)象就被銷毀了今魔。
多例對(duì)象:scope="prototype"
每次訪問對(duì)象時(shí),都會(huì)重新創(chuàng)建對(duì)象實(shí)例障贸。
? 生命周期:
對(duì)象出生:當(dāng)使用對(duì)象時(shí),創(chuàng)建新的對(duì)象實(shí)例。
對(duì)象活著:只要對(duì)象在使用中,就一直活著问词。
對(duì)象死亡:當(dāng)對(duì)象長(zhǎng)時(shí)間不用時(shí),被 java 的垃圾回收器回收了激挪。
3.3.2.3 實(shí)例化 Bean 的三種方式
第一種方式:使用默認(rèn)無參構(gòu)造函數(shù)
<!--在默認(rèn)情況下:
它會(huì)根據(jù)默認(rèn)無參構(gòu)造函數(shù)來創(chuàng)建類對(duì)象锋叨。如果 bean 中沒有默認(rèn)無參構(gòu)造函數(shù),將會(huì)創(chuàng)建失敗娃磺。
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
第二種方式:spring 管理靜態(tài)工廠-使用靜態(tài)工廠的方法創(chuàng)建對(duì)象
/**
* 模擬一個(gè)靜態(tài)工廠,創(chuàng)建業(yè)務(wù)層實(shí)現(xiàn)類
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此種方式是:
使用 StaticFactory 類中的靜態(tài)方法 createAccountService 創(chuàng)建對(duì)象,并存入 spring 容器
id 屬性:指定 bean 的 id,用于從容器中獲取
class 屬性:指定靜態(tài)工廠的全限定類名
factory-method 屬性:指定生產(chǎn)對(duì)象的靜態(tài)方法
-->
<bean id="accountService" class="com.itheima.factory.StaticFactory"
factory-method="createAccountService"></bean>
第三種方式:spring 管理實(shí)例工廠-使用實(shí)例工廠的方法創(chuàng)建對(duì)象
/**
* 模擬一個(gè)實(shí)例工廠,創(chuàng)建業(yè)務(wù)層實(shí)現(xiàn)類
* 此工廠創(chuàng)建對(duì)象,必須現(xiàn)有工廠實(shí)例對(duì)象,再調(diào)用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此種方式是:
先把工廠的創(chuàng)建交給 spring 來管理偷卧。
然后在使用工廠的 bean 來調(diào)用里面的方法
factory-bean 屬性:用于指定實(shí)例工廠 bean 的 id。
factory-method 屬性:用于指定實(shí)例工廠中創(chuàng)建對(duì)象的方法坐求。
-->
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instancFactory"
factory-method="createAccountService"></bean>
3.3.3 spring 的依賴注入
3.3.3.1 依賴注入的概念
? 依賴注入:Dependency Injection
桥嗤。它是 spring 框架核心 ioc
的具體實(shí)現(xiàn)仔蝌。
我們的程序在編寫時(shí),通過控制反轉(zhuǎn),把對(duì)象的創(chuàng)建交給了 spring,但是代碼中不可能出現(xiàn)沒有依賴的情況敛惊。ioc 解耦只是降低他們的依賴關(guān)系,但不會(huì)消除。例如:我們的業(yè)務(wù)層仍會(huì)調(diào)用持久層的方法篓像。
那這種業(yè)務(wù)層和持久層的依賴關(guān)系,在使用 spring 之后,就讓 spring 來維護(hù)了皿伺。
簡(jiǎn)單的說,就是坐等框架把持久層對(duì)象傳入業(yè)務(wù)層,而不用我們自己去獲取鸵鸥。
3.3.3.2 構(gòu)造函數(shù)注入
? 顧名思義,就是使用類中的構(gòu)造函數(shù),給成員變量賦值。注意,賦值的操作不是我們自己做的,而是通過配置的方式,讓 spring 框架來為我們注入宋税。具體代碼如下:
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
<!-- 使用構(gòu)造函數(shù)的方式,給 service 中的屬性傳值
要求:
類中需要提供一個(gè)對(duì)應(yīng)參數(shù)列表的構(gòu)造函數(shù)杰赛。
涉及的標(biāo)簽:
constructor-arg
屬性:
index:指定參數(shù)在構(gòu)造函數(shù)參數(shù)列表的索引位置
type:指定參數(shù)在構(gòu)造函數(shù)中的數(shù)據(jù)類型 用這個(gè)找給誰賦值
name:指定參數(shù)在構(gòu)造函數(shù)中的名稱
=======上面三個(gè)都是找給誰賦值,下面兩個(gè)指的是賦什么值的==============
value:它能賦的值是基本數(shù)據(jù)類型和 String 類型
ref:它能賦的值是其他 bean 類型,也就是說,必須得是在配置文件中配置過的 bean
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value=" 張三 "></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>
3.3.3.3 set 方法注入
? 顧名思義,就是在類中提供需要注入成員的 set 方法乏屯。具體代碼如下:
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
<!-- 通過配置文件給 bean 中的屬性傳值:使用 set 方法的方式
涉及的標(biāo)簽:
property
屬性:
name:找的是類中 set 方法后面的部分
ref:給屬性賦值是其他 bean 類型的
value:給屬性賦值是基本數(shù)據(jù)類型和 string 類型的
實(shí)際開發(fā)中,此種方式用的較多辰晕。
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="name" value="test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>
3.3.3.4 使用 p 名稱空間注入數(shù)據(jù)(本質(zhì)還是調(diào)用 set 方法)
? 此種方式是通過在 xml 中導(dǎo)入 p 名稱空間,使用 p:propertyName 來注入數(shù)據(jù),它的本質(zhì)仍然是調(diào)用類中的set 方法實(shí)現(xiàn)注入功能含友。
public class AccountServiceImpl4 implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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="accountService"
class="com.itheima.service.impl.AccountServiceImpl4"
p:name="test" p:age="21" p:birthday-ref="now"/>
</beans>
3.3.3.5 注入集合屬性
? 顧名思義,就是給類中的集合成員傳值,它用的也是 set 方法注入的方式,只不過變量的數(shù)據(jù)類型都是集合窘问。我們這里介紹注入數(shù)組,List,Set,Map,Properties宜咒。具體代碼如下:
public class AccountServiceImpl implements IAccountService {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
@Override
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
<!-- 注入集合數(shù)據(jù)
List 結(jié)構(gòu)的:
array,list,set
Map 結(jié)構(gòu)的
map,entry,props,prop
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!-- 在注入集合數(shù)據(jù)時(shí),只要結(jié)構(gòu)相同,標(biāo)簽可以互換 -->
<!-- 給數(shù)組注入數(shù)據(jù) -->
<property name="myStrs">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<!-- 注入 list 集合數(shù)據(jù) -->
<property name="myList">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<!-- 注入 set 集合數(shù)據(jù) -->
<property name="mySet">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<!-- 注入 Map 數(shù)據(jù) -->
<property name="myMap">
<props>
<prop key="testA">aaa</prop>
<prop key="testB">bbb</prop>
</props>
</property>
<!-- 注入 properties 數(shù)據(jù) -->
<property name="myProps">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB">
<value>bbb</value>
</entry>
</map>
</property>
</bean>