前言
歡迎來到本篇文章!通過上一篇什么是 Spring?為什么學(xué)它?的學(xué)習(xí),我們知道了 Spring 的基本概念,知道什么是 Spring,以及為什么學(xué)習(xí) Spring。今天,這篇就來說說 Spring 中的核心概念之一 IoC。
IoC 這個概念對于初學(xué)者來說還真不是很好理解,我就是那個理解不了的初學(xué)者。那時候,學(xué)起來很費(fèi)解,只是迷迷糊糊知道了一些概念名詞,控制反轉(zhuǎn),依賴注入。
現(xiàn)在,我重新梳理這些知識,盡量寫清楚什么是 IoC 以及相關(guān)的知識,如有錯誤,敬請指正!好了廢話不多說,進(jìn)入正題!
什么是 IoC?什么是 Spring IoC 容器?
IoC(Inversion of Control),即控制反轉(zhuǎn),也被稱為依賴注入(Dependency Injection,DI)。
如果有對「依賴」不太明白的朋友,那么可以去看上一篇,在上一篇中,我們通過 Employee 和 Department 的例子解釋了何為「依賴」
IoC 是一種定義對象之間依賴關(guān)系的過程。
在 Spring 沒出現(xiàn)之前,當(dāng)一個對象需要使用其他對象來完成某些操作,就需要我們自己去創(chuàng)建或查找這些依賴的對象。
現(xiàn)在,有了 Spring,我們的對象交給 Spring 管理,這些對象可以理解為存放在一個容器中的,這個容器就稱為 Spring IoC容器。在 IoC 容器中,對象不再自己管理它們的依賴,而是通過構(gòu)造方法參數(shù)、工廠方法的參數(shù)或者在對象創(chuàng)建后通過屬性設(shè)置來定義它們的依賴關(guān)系。
Spring 的 IoC 容器負(fù)責(zé)在創(chuàng)建對象時注入它們依賴的其他對象,也就是自動地把依賴的對象提供給需要它們的對象。這樣一來,對象不再需要主動去查找或創(chuàng)建它們的依賴,而是由容器在創(chuàng)建對象時幫助它們完成依賴注入的過程。
控制反轉(zhuǎn)的概念主要是與傳統(tǒng)的直接構(gòu)造(即 new
操作)來控制對象依賴的方式相反。傳統(tǒng)方式中,一個對象通常會直接創(chuàng)建或查找它所依賴的其他對象,而在 IoC 中,對象將自身的控制權(quán)交給了容器,容器負(fù)責(zé)管理對象的創(chuàng)建和依賴注入,因此被稱為「控制反轉(zhuǎn)」。
初次見面 BeanFactory 和 ApplicationContext
在 Spring Framework 中,org.springframework.beans
和 org.springframework.context
包是 Spring IoC 容器的基礎(chǔ)。
下面介紹兩個新手村的伙伴給大家認(rèn)識,BeanFactory
接口和它的子接口 ApplicationContext
接口。
BeanFactory
接口提供了一個高級配置機(jī)制,能夠管理任何類型的對象。
對于它的子接口 ApplicationContext
來說,它的子接口增加了以下功能:
-
更容易與 Spring AOP 特性集成
-
消息資源處理(用于國際化)
-
事件發(fā)布
-
應(yīng)用程序?qū)犹囟ㄉ舷挛?,例?WebApplicationContext,用于 Web 應(yīng)用程序。
簡而言之,BeanFactory
提供配置框架和基本功能,而 ApplicationContext
添加了更多企業(yè)特定功能。
什么是 Bean?
在 Spring 中,構(gòu)成應(yīng)用程序骨干并由 Spring IoC 容器管理的對象稱為 Bean。 Bean 是由 Spring IoC 容器實(shí)例化、組裝和管理的對象。否則,Bean 只是我們應(yīng)用程序中眾多對象中的一個普通的對象而已。
Bean 及其相互依賴關(guān)系是反映在容器使用的配置元數(shù)據(jù)(Configuration Metadata)中的,這個配置元數(shù)據(jù)可以用 XML、Java 注解或 Java 代碼表示。
提示:如果你和我一樣比較喜歡深究這些英文單詞的中文意思,現(xiàn)在的我給你個建議:
就是覺得沒必要深究!
比如說 Bean,中文是什么意思,你去找翻譯,發(fā)現(xiàn)翻譯是「豆」,還有類似 JavaBean,翻譯是「Java 豆」,這些都是毫無意義的翻譯,所以沒必要知道它的中文意思是什么,Bean 就是 Bean,Bean 就是被 Spring IoC 容器管理的對象,這就是 Bean;JavaBean 則是只提供 setter 和 getter 的純對象,本身沒有任何業(yè)務(wù)邏輯,這就是 JavaBean。
容器是誰?
我們一直談到「容器」,那么容器到底是什么呢?嘿嘿,容器馬上就揭曉了!
實(shí)際上,Spring 的 IoC 容器就是由 org.springframework.context.ApplicationContext
接口來代表的。這個容器承擔(dān)著實(shí)例化、配置和組裝Bean的責(zé)任。
容器通過讀取配置元數(shù)據(jù)來了解如何創(chuàng)建、配置和組裝對象,同時也允許我們描述應(yīng)用程序中各個對象之間的復(fù)雜依賴關(guān)系。目前從本系列的角度來看,我們會使用傳統(tǒng)的 XML 方式來定義配置元數(shù)據(jù),這是我們需要學(xué)習(xí)和了解的,后續(xù)才能更好地理解使用 Java 注解或代碼作為配置元數(shù)據(jù)的方式。
Spring 為我們提供了多個 ApplicationContext
接口的實(shí)現(xiàn)。在獨(dú)立的應(yīng)用程序中,常見的實(shí)例化方式是創(chuàng)建 ClassPathXmlApplicationContext
或 FileSystemXmlApplicationContext
的一個實(shí)例。
不過,在我們?nèi)粘5拈_發(fā)和工作中,我們基本上不需要顯式地去實(shí)例化一個或多個 Spring 容器。特別是在Web應(yīng)用程序的場景下,通常只需在web.xml
文件中簡單地編寫約8行標(biāo)準(zhǔn)的XML配置即可完成(你可以參考一些方便的方式來初始化Web應(yīng)用程序的ApplicationContext)。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
所以,容器終于來啦!它就是 Spring 的 IoC 容器,負(fù)責(zé)管理 Bean 的實(shí)例化、配置和組裝,而我們可以通過配置元數(shù)據(jù)來描述應(yīng)用程序中的對象和它們之間的依賴關(guān)系。記住,我們一般不需要手動實(shí)例化 Spring 容器,特別是在 Web 應(yīng)用程序中。
Spring IoC 容器怎樣運(yùn)行的?
從頂層上來看,Spring IoC 是這樣運(yùn)行的,就是將我們應(yīng)用程序中的各種業(yè)務(wù)對象與配置元數(shù)據(jù)結(jié)合起來,使得我們在初始化 ApplicationContext 之后,有一個完整配置的、可用的應(yīng)用程序。
什么是配置元數(shù)據(jù)?
先說個結(jié)論,目前日常工作中,配置元數(shù)據(jù)基本都是以 Java 注解或者 Java 代碼的方式來提供給 Spring 容器的,不過 XML 的方式我們也要學(xué)習(xí),對于后續(xù)學(xué)習(xí)是有幫助的。
「配置元數(shù)據(jù)」是 Configuration Metadata,不是 Configure Metadata,這里的「配置」二字是名詞,不是動詞,千萬不要理解成去配置元數(shù)據(jù)。
這個配置元數(shù)據(jù),實(shí)際就是用來描述配置的數(shù)據(jù),上面我也說了,我們可以用 Java 注解或者 Java 代碼的方式來描述配置,也可以用 XML 的方式來描述數(shù)據(jù)。
所以現(xiàn)在,相信你已經(jīng)明白何為配置元數(shù)據(jù)了,所以學(xué)習(xí)下以 XML 格式的文件作為配置元數(shù)據(jù)。
XML 格式的配置元數(shù)據(jù)
配置元數(shù)據(jù)以簡單直觀的 XML 格式提供,這也是本系列前大半部分內(nèi)容用來傳達(dá) Spring IoC 容器關(guān)鍵概念和特性的方式,也正如前面說的,學(xué)習(xí) XML 的配置方式,便于我們后續(xù)學(xué)習(xí) Java 注解或者 Java 代碼的配置方式。
下面的示例展示了基于XML的配置元數(shù)據(jù)的基本結(jié)構(gòu):
<?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">
<bean id="..." class="...">
<!-- 該 bean 的協(xié)作者和配置寫在此處 -->
</bean>
<bean id="..." class="...">
<!-- 該 bean 的協(xié)作者和配置寫在此處 -->
</bean>
<!-- 更多的 bean 定義寫在此處 -->
</beans>
上面的示例中,主要使用了 <bean>
元素(或者說標(biāo)簽),該元素有兩個屬性,id
和 class
:
-
id
屬性:它是一個字符串,用于標(biāo)識單個 bean 定義。 -
class
屬性:它定義了 bean 的類型,并使用完全限定類名(又稱全限定名、全類名。多種叫法,都是同一個東西)。
我們習(xí)慣說把對象交給 Spring IoC 容器管理,那你如何個交法呢?
上面的 XML 已經(jīng)給出了答案,就是定義 Bean,我們每定義一個 Bean,就是將對應(yīng)的類的對象交給了 Spring IoC 容器了。
這些 Bean 的定義就是構(gòu)成我們應(yīng)用程序中的各種實(shí)際對象。一般我們在開發(fā)的時候,都會分層次的,控制層、業(yè)務(wù)層、持久層、表現(xiàn)層(視圖層)或者其他層次,然后我們就會定義業(yè)務(wù)層對象、持久層對象、表現(xiàn)層對象等等。
在上一篇中,我舉了個例子,員工和部門的,讓這兩個東西交給了 Spring IoC 管理了,實(shí)際上,在日常開發(fā)中,是不會這樣做的,不會配置細(xì)粒度的領(lǐng)域?qū)ο螅―omain Object)。因?yàn)橐话氵@些領(lǐng)域?qū)ο蠖际窃跇I(yè)務(wù)層和持久層中創(chuàng)建或者加載的。
如何實(shí)例化一個 Spring IoC 容器?
上面我也說過,在我們?nèi)粘5拈_發(fā)和工作中,我們基本上不需要顯式地去實(shí)例化一個或多個 Spring 容器的。
但是我們現(xiàn)在在學(xué)習(xí),就有必要了解如何手動去實(shí)例化一個 Spring IoC 容器。
一行代碼就能夠?qū)嵗粋€ Spring IoC 容器:
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
在 XML 為配置元數(shù)據(jù)的情況下,我們可以創(chuàng)建一個 ClassPathXmlApplicationContext
對象,它是 ApplicationContext
的一個實(shí)現(xiàn)類,提供給我們的構(gòu)造函數(shù)的參數(shù)是一條或多條路徑是資源字符串,它讓容器從各種外部資源(如本地文件系統(tǒng)、Java CLASSPATH
等)加載配置元數(shù)據(jù),這樣我們就實(shí)例化一個 Spring IoC 容器,context
對象就是這個容器了。
現(xiàn)在我們將持久層的對象和業(yè)務(wù)層的對象定義到 XML 中,先創(chuàng)建好需要的類和接口:
接著,在 daos.xml
中定義如下兩個 bean,交給 Spring IoC 管理:
<?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="roleDao" class="cn.god23bin.demo.dao.impl.RoleDaoImpl">
<!-- 該 bean 的協(xié)作者和其他配置 -->
</bean>
<bean id="userDao" class="cn.god23bin.demo.dao.impl.UserDaoImpl">
<!-- 該 bean 的協(xié)作者和其他配置 -->
</bean>
<!-- 其他的持久層的 bean 定義在這里 -->
</beans>
services.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">
<!-- 引入另一個 XML 定義的 bean -->
<import resource="daos.xml"/>
<bean id="userService" class="cn.god23bin.demo.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao" />
<property name="roleDao" ref="roleDao" />
</bean>
<!-- 其他的業(yè)務(wù)層的 bean 定義在這里 -->
</beans>
在 services.xml
中,使用 <import />
可以讓 Bean 的定義跨越 XML 文件。一般每個單獨(dú)的 XML 配置文件代表了我們應(yīng)用中的一個邏輯層或者模塊,就如同這里的 daos.xml
和 services.xml
。
使用 Spring IoC 容器
我們把對象交給了 Spring IoC 容器管理,讓它幫我們創(chuàng)建對象以及處理對象之間的依賴關(guān)系。
在上面的 XML 中,我們定義了 UserServcie 對象,即把 UserService 這個對象交給了 Spring IoC,那么如何從容器獲取它呢?
ApplicationContext
是一個高級工廠的接口,能夠維護(hù)不同 Bean 及其依賴關(guān)系的注冊表。我們通過使用方法 T getBean(String name, Class requiredType)
,就可以獲取到我們需要的 Bean 對象。
代碼如下:
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
UserService userService = context.getBean("userService", UserService.class);
String roleList = userService.getRoleList();
String username1 = userService.getUsernameById(23L);
String username2 = userService.getUsernameById(24L);
System.out.println("roleList = " + roleList + " | username1 = " + username1 + " | username2 = " + username2);
輸出:
總結(jié)
以上,就是本文的所有內(nèi)容,主要講了什么是 Spring IoC 容器,介紹了 BeanFactory 和 ApplicationContext。
實(shí)際上這個 ApplicationContext 就代表容器,它會讀取我們的配置元數(shù)據(jù),這樣它就知道該去管理哪些對象了。
也介紹了什么是 Bean,實(shí)際上就是被容器管理的對象,都是所謂的 Bean,也習(xí)慣稱為 Bean 對象。
還介紹了 Spring IoC 容器從頂層上來看是怎樣運(yùn)行的,就是將各種業(yè)務(wù)對象和配置元數(shù)據(jù)相結(jié)合,組成一個完整配置的、可用的應(yīng)用程序。
對于配置元數(shù)據(jù),這個可以有多種形式,可以是 XML,可以是 Java 注解,可以是 Java 代碼。
最后就介紹了如何去實(shí)例化并使用 Spring IoC 容器,雖然我們?nèi)粘i_始是不會這樣去做的,不會去創(chuàng)建一個容器,然后通過容器的 getBean 去獲取 Bean 進(jìn)行操作,但是我們就是需要了解學(xué)習(xí),因?yàn)檫@些就是 Spring 的基礎(chǔ)。
最后的最后
希望各位屏幕前的靚仔靚女們
給個三連!你輕輕地點(diǎn)了個贊,那將在我的心里世界增添一顆明亮而耀眼的星!文章來源:http://www.zghlxwxcb.cn/news/detail-469578.html
咱們下期再見!文章來源地址http://www.zghlxwxcb.cn/news/detail-469578.html
到了這里,關(guān)于Spring 核心概念之一 IoC的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!