從本文開(kāi)始,將開(kāi)始介紹關(guān)于 Spring 的一些常見(jiàn)知識(shí)點(diǎn)。關(guān)注我的公眾號(hào)「Java面典」,每天 10:24 和你一起了解更多 Java 相關(guān)知識(shí)點(diǎn)。
在如今的 Java Web 開(kāi)發(fā)中,Spring 生態(tài)圈占據(jù)著巨大的市場(chǎng)份額。幾乎是每個(gè)互聯(lián)網(wǎng)公司都在用 Spring 生態(tài)圈的東西。所以掌握Spring 相關(guān)知識(shí)就成為了我們工作和面試中必不可少的技能。今天將為各位帶來(lái) Spring IOC 的相關(guān)知識(shí)。
IOC —— Inversion of Control,即“控制反轉(zhuǎn)”,不是什么技術(shù),而是一種設(shè)計(jì)思想。指的是將設(shè)計(jì)好的對(duì)象交給容器控制,而不是傳統(tǒng)的在對(duì)象內(nèi)部直接控制。
Spring 的 IOC 實(shí)現(xiàn)離不了DI(DI——Dependency Injection,即“依賴(lài)注入”。依賴(lài)注入指的是由容器動(dòng)態(tài)的將某個(gè)依賴(lài)關(guān)系注入到組件之中)。
Spring 通過(guò)一個(gè)配置文件描述 Bean 及 Bean 之間的依賴(lài)關(guān)系,利用 Java 語(yǔ)言的反射功能實(shí)例化 Bean 并建立 Bean 之間的依賴(lài)關(guān)系。
IOC 容器主要由 BeanFactory 和 ApplicationContext 組成。BeanFactory 是 Spring 框架的基礎(chǔ)設(shè)施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的開(kāi)發(fā)者,幾乎所有的應(yīng)用場(chǎng)合我們都直接使用 ApplicationContext 而非底層的 BeanFactory。
BeanFactory 是 Spring 框架的基礎(chǔ)設(shè)施,面向 Spring 本身,BeanFactory 主要有以下組件:
BeanDefinitionRegistry:注冊(cè)表,提供了向容器手工注冊(cè) BeanDefinition 對(duì)象的方法。Spring 配置文件中每一個(gè)節(jié)點(diǎn)元素在 Spring 容器里都通過(guò)一個(gè) BeanDefinition 對(duì)象表示,它描述了 Bean 的配置信息;
BeanFactory:頂層接口。它最主要的方法就是 getBean(String beanName),該方法從容器中返回特定名稱(chēng)的 Bean;
ListableBeanFactory:該接口定義了訪問(wèn)容器中 Bean 基本信息的若干方法,如查看 Bean 的個(gè)數(shù)、獲取某一類(lèi)型 Bean 的配置名、查看容器中是否包括某一 Bean 等方法;
HierarchicalBeanFactory:父子級(jí)聯(lián) IOC 容器的接口,子容器可以通過(guò)接口方法訪問(wèn)父容器; 通過(guò)HierarchicalBeanFactory 接口, Spring 的 IOC 容器可以建立父子層級(jí)關(guān)聯(lián)的容器體系,子容器可以訪問(wèn)父容器中的 Bean,但父容器不能訪問(wèn)子容器的 Bean。Spring 使用父子容器實(shí)現(xiàn)了很多功能,比如在 Spring MVC 中,展現(xiàn)層 Bean 位于一個(gè)子容器中,而業(yè)務(wù)層和持久層的 Bean 位于父容器中。這樣,展現(xiàn)層 Bean 就可以引用業(yè)務(wù)層和持久層的 Bean,而業(yè)務(wù)層和持久層的 Bean 則看不到展現(xiàn)層的 Bean;
ConfigurableBeanFactory:定義了設(shè)置類(lèi)裝載器、屬性編輯器、容器初始化后置處理器等方法,增強(qiáng)了 IOC 容器的可定制性;
AutowireCapableBeanFactory:定義了將容器中的 Bean 按某種規(guī)則(如按名字匹配、按類(lèi)型匹配等)進(jìn)行自動(dòng)裝配的方法;
SingletonBeanRegistry:定義了允許在運(yùn)行期間向容器注冊(cè)單實(shí)例 Bean 的方法;對(duì)于單實(shí)例( singleton)的 Bean 來(lái)說(shuō),BeanFactory 會(huì)緩存 Bean 實(shí)例,所以第二次使用 getBean() 獲取 Bean 時(shí)將直接從IOC 容器的緩存中獲取 Bean 實(shí)例。Spring 在 DefaultSingletonBeanRegistry 類(lèi)中提供了一個(gè)用于緩存單實(shí)例 Bean 的緩存器,它是一個(gè)用 HashMap 實(shí)現(xiàn)的緩存器,單實(shí)例的 Bean 以 beanName 為鍵保存在這個(gè) HashMap 中。
依賴(lài)日志框架:在初始化 BeanFactory 時(shí),必須為其提供一種日志框架,比如使用 Log4J, 即在類(lèi)路徑下提供 Log4J 配置文件,這樣啟動(dòng) Spring 容器才不會(huì)報(bào)錯(cuò)。
ApplicationContext 由 BeanFactory 派 生 而 來(lái) , 提 供 了 更 多 面 向 實(shí) 際 應(yīng) 用 的 功 能 。ApplicationContext 繼承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基礎(chǔ)上,還通過(guò)多個(gè)其他的接口擴(kuò)展了 BeanFactory 的功能:
WebApplicationContext 是專(zhuān)門(mén)為 Web 應(yīng)用準(zhǔn)備的,它允許從相對(duì)于 Web 根目錄的路徑中裝載配置文件完成初始化工作。從 WebApplicationContext 中可以獲得ServletContext 的引用,整個(gè) Web 應(yīng)用上下文對(duì)象將作為屬性放置到 ServletContext 中,以便 Web 應(yīng)用環(huán)境可以訪問(wèn) Spring 應(yīng)用上下文。
/*帶參數(shù),方便利用構(gòu)造器進(jìn)行注入*/public CatDaoImpl(String message){ this. message = message; } <bean id="CatDaoImpl" class="com.CatDaoImpl"> <constructor-arg value=" message "></constructor-arg> </bean>
private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } <bean id="id" class="com.id "> <property name="id" value="123"></property> </bean>
靜態(tài)工廠顧名思義,就是通過(guò)調(diào)用靜態(tài)工廠的方法來(lái)獲取自己需要的對(duì)象,為了讓 Spring 管理所有對(duì)象,我們不能直接通過(guò)"工程類(lèi).靜態(tài)方法()"來(lái)獲取對(duì)象,而是依然通過(guò) Spring 注入的形式獲?。?/p>
public class DaoFactory { //靜態(tài)工廠 public static final FactoryDao getStaticFactoryDaoImpl(){ return new StaticFacotryDaoImpl(); } } public class SpringAction { //注入對(duì)象 private FactoryDao staticFactoryDao; //注入對(duì)象的 set 方法 public void setStaticFactoryDao(FactoryDao staticFactoryDao) { this.staticFactoryDao = staticFactoryDao; } } <bean name="springAction" class=" SpringAction" > <!--使用靜態(tài)工廠的方法注入對(duì)象,對(duì)應(yīng)下面的配置文件--> <property name="staticFactoryDao" ref="staticFactoryDao"></property> </bean> <!--此處獲取對(duì)象的方式是從工廠類(lèi)中獲取靜態(tài)方法--> <bean name="staticFactoryDao" class="DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
實(shí)例工廠的意思是獲取對(duì)象實(shí)例的方法不是靜態(tài)的,所以你需要首先 new 工廠類(lèi),再調(diào)用普通的實(shí)例方法:
public class DaoFactory { //實(shí)例工廠 public FactoryDao getFactoryDaoImpl(){ return new FactoryDaoImpl(); } } public class SpringAction { private FactoryDao factoryDao; //注入對(duì)象 public void setFactoryDao(FactoryDao factoryDao) { this.factoryDao = factoryDao; } } <bean name="springAction" class="SpringAction"> <!--使用實(shí)例工廠的方法注入對(duì)象,對(duì)應(yīng)下面的配置文件--> <property name="factoryDao" ref="factoryDao"></property> </bean> <!--此處獲取對(duì)象的方式是從工廠類(lèi)中獲取實(shí)例方法--> <bean name="daoFactory" class="com.DaoFactory"></bean> <bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
Spring 裝配包括手動(dòng)裝配和自動(dòng)裝配,手動(dòng)裝配是有基于 xml 裝配、構(gòu)造方法、setter 方法等;自動(dòng)裝配有五種方式,可以用來(lái)指導(dǎo) Spring 容器用自動(dòng)裝配方式來(lái)進(jìn)行依賴(lài)注入:
注意:使用 byType 首先需要保證同一類(lèi)型的對(duì)象,在 Spring 容器中唯一,若不唯一會(huì)報(bào)不唯一的異常。
聯(lián)系客服