Spring中的ApplicationContext與BeanFactory詳解
前言
Spring的IoC容器就是一個(gè)實(shí)現(xiàn)了BeanFactory接口的可實(shí)例化類(lèi)。
事實(shí)上, Spring提供了兩種不同的容器:一種是最基本的BeanFactory,另一種是擴(kuò)展的ApplicationContext。
一、BeanFactory
BeanFactory 是 Spring 的“心臟”。它就是 Spring IoC 容器的真面目。Spring 使用 BeanFactory 來(lái)實(shí)例化、配置和管理 Bean。
BeanFactory:是IOC容器的核心接口, 它定義了IOC的基本功能,我們看到它主要定義了getBean方法。getBean方法是IOC容器獲取bean對(duì)象和引發(fā)依賴(lài)注入的起點(diǎn)。方法的功能是返回特定名稱(chēng)的Bean。
BeanFactory 是初始化 Bean 和調(diào)用它們生命周期方法的“吃苦耐勞者”。
注意,BeanFactory 只能管理單例(Singleton)Bean 的生命周期。
它不能管理原型(prototype,非單例)Bean 的生命周期。這是因?yàn)樵?Bean 實(shí)例被創(chuàng)建之后便被傳給了客戶(hù)端,容器失去了對(duì)它們的引用。
BeanFactory有著龐大的繼承、實(shí)現(xiàn)體系,有眾多的子接口、實(shí)現(xiàn)類(lèi)。來(lái)看一下BeanFactory的基本類(lèi)體系結(jié)構(gòu)(接口為主):

這是我畫(huà)的BeanFactory基本的類(lèi)體系結(jié)構(gòu),這里沒(méi)有包括強(qiáng)大的ApplicationContext體系。
具體:
1、BeanFactory作為一個(gè)主接口不繼承任何接口,暫且稱(chēng)為一級(jí)接口。
2、有3個(gè)子接口繼承了它,進(jìn)行功能上的增強(qiáng)。這3個(gè)子接口稱(chēng)為二級(jí)接口。
3、ConfigurableBeanFactory可以被稱(chēng)為三級(jí)接口,對(duì)二級(jí)接口HierarchicalBeanFactory進(jìn)行了再次增強(qiáng),它還繼承了另一個(gè)外來(lái)的接口SingletonBeanRegistry
4、ConfigurableListableBeanFactory是一個(gè)更強(qiáng)大的接口,繼承了上述的所有接口,無(wú)所不包,稱(chēng)為四級(jí)接口。(這4級(jí)接口是BeanFactory的基本接口體系。繼續(xù),下面是繼承關(guān)系的2個(gè)抽象類(lèi)和2個(gè)實(shí)現(xiàn)類(lèi):)
5、AbstractBeanFactory作為一個(gè)抽象類(lèi),實(shí)現(xiàn)了三級(jí)接口ConfigurableBeanFactory大部分功能。
6、AbstractAutowireCapableBeanFactory同樣是抽象類(lèi),繼承自AbstractBeanFactory,并額外實(shí)現(xiàn)了二級(jí)接口AutowireCapableBeanFactory
7、DefaultListableBeanFactory繼承自AbstractAutowireCapableBeanFactory,實(shí)現(xiàn)了最強(qiáng)大的四級(jí)接口ConfigurableListableBeanFactory,并實(shí)現(xiàn)了一個(gè)外來(lái)接口BeanDefinitionRegistry,它并非抽象類(lèi)。
8、最后是最強(qiáng)大的XmlBeanFactory,繼承自DefaultListableBeanFactory,重寫(xiě)了一些功能,使自己更強(qiáng)大。
總結(jié): BeanFactory的類(lèi)體系結(jié)構(gòu)看似繁雜混亂,實(shí)際上由上而下井井有條,非常容易理解。
再來(lái)看一下BeanFactory的源碼:
package org.springframework.beans.factory;
public interface BeanFactory {
/*
* 用來(lái)引用一個(gè)實(shí)例,或把它和工廠(chǎng)產(chǎn)生的Bean區(qū)分開(kāi),就是說(shuō),如果一個(gè)FactoryBean的名字為a,那么,&a會(huì)得到那個(gè)Factory
*/
String FACTORY_BEAN_PREFIX = "&";
/*
* 四個(gè)不同形式的getBean方法,獲取實(shí)例
*/
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
boolean containsBean(String name); // 是否存在
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 是否為單實(shí)例
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 是否為原型(多實(shí)例)
boolean isTypeMatch(String name, Class<?> targetType)
throws NoSuchBeanDefinitionException;// 名稱(chēng)、類(lèi)型是否匹配
Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 獲取類(lèi)型
String[] getAliases(String name);// 根據(jù)實(shí)例的名字獲取實(shí)例的別名
}具體:
1、4個(gè)獲取實(shí)例的方法。getBean的重載方法。
2、4個(gè)判斷的方法。判斷是否存在,是否為單例、原型,名稱(chēng)類(lèi)型是否匹配。
3、1個(gè)獲取類(lèi)型的方法、一個(gè)獲取別名的方法。根據(jù)名稱(chēng)獲取類(lèi)型、根據(jù)名稱(chēng)獲取別名。一目了然!
總結(jié): 這10個(gè)方法,很明顯,這是一個(gè)典型的工廠(chǎng)模式的工廠(chǎng)接口。
BeanFactory最常見(jiàn)的實(shí)現(xiàn)類(lèi)為XmlBeanFactory,可以從classpath或文件系統(tǒng)等獲取資源。
File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);Resource resource = new ClassPathResource("classpath.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);XmlBeanFactory可以加載xml的配置文件。假設(shè)我們有一個(gè)Car類(lèi):
package spring.ioc.demo1;
public class Car {
private String brand;
private String color;
private int maxSpeed;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public String toString(){
return "the car is:"+ getBrand() + ", color is:" +getColor() +", maxspeed is:"+getMaxSpeed();
}
public Car() {
}
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public void introduce() {
System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:"
+ maxSpeed);
}
}我們通過(guò)在applicationContext.xml中配置:
<bean id="car1" class="spring.ioc.demo1.Car"
p:brand="spring注入-紅旗001"
p:color="spring注入-紫色"
p:maxSpeed="520" />通過(guò)XmlBeanFactory實(shí)現(xiàn)啟動(dòng)Spring IoC容器:
public static void main(String[] args) {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource res = resolver.getResource("classpath:applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(res);
//ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = factory.getBean("car1",Car.class);
System.out.println("car對(duì)象已經(jīng)初始化完成");
System.out.println(car.getMaxSpeed());
}1. XmlBeanFactory通過(guò)Resource裝載Spring配置信息并啟動(dòng)IoC容器,然后就可以通過(guò)factory.getBean從IoC容器中獲取Bean了。
2. 通過(guò)BeanFactory啟動(dòng)IoC容器時(shí),并不會(huì)初始化配置文件中定義的Bean,初始化動(dòng)作發(fā)生在第一個(gè)調(diào)用時(shí)。
3. 對(duì)于單實(shí)例(singleton)的Bean來(lái)說(shuō),BeanFactory會(huì)緩存Bean實(shí)例,所以第二次使用getBean時(shí)直接從IoC容器緩存中獲取Bean。
二、ApplicationContext
如果說(shuō)BeanFactory是Spring的心臟,那么ApplicationContext就是完整的軀體了,ApplicationContext由BeanFactory派生而來(lái),提供了更多面向?qū)嶋H應(yīng)用的功能。在BeanFactory中,很多功能需要以編程的方式實(shí)現(xiàn),而在ApplicationContext中則可以通過(guò)配置實(shí)現(xiàn)。
BeanFactorty接口提供了配置框架及基本功能,但是無(wú)法支持spring的aop功能和web應(yīng)用。而ApplicationContext接口作為BeanFactory的派生,因而提供BeanFactory所有的功能。而且ApplicationContext還在功能上做了擴(kuò)展,相較于BeanFactorty,ApplicationContext還提供了以下的功能:
(1)MessageSource, 提供國(guó)際化的消息訪(fǎng)問(wèn)
(2)資源訪(fǎng)問(wèn),如URL和文件
(3)事件傳播特性,即支持aop特性
(4)載入多個(gè)(有繼承關(guān)系)上下文 ,使得每一個(gè)上下文都專(zhuān)注于一個(gè)特定的層次,比如應(yīng)用的web層
ApplicationContext:是IOC容器另一個(gè)重要接口, 它繼承了BeanFactory的基本功能, 同時(shí)也繼承了容器的高級(jí)功能,如:MessageSource(國(guó)際化資源接口)、ResourceLoader(資源加載接口)、ApplicationEventPublisher(應(yīng)用事件發(fā)布接口)等。
三、二者區(qū)別
- BeanFactroy采用的是延遲加載形式來(lái)注入Bean的,即只有在使用到某個(gè)Bean時(shí)(調(diào)用getBean()),才對(duì)該Bean進(jìn)行加載實(shí)例化,這樣,我們就不能發(fā)現(xiàn)一些存在的Spring的配置問(wèn)題。而ApplicationContext則相反,它是在容器啟動(dòng)時(shí),一次性創(chuàng)建了所有的Bean。這樣,在容器啟動(dòng)時(shí),我們就可以發(fā)現(xiàn)Spring中存在的配置錯(cuò)誤。 相對(duì)于基本的BeanFactory,ApplicationContext 唯一的不足是占用內(nèi)存空間。當(dāng)應(yīng)用程序配置Bean較多時(shí),程序啟動(dòng)較慢。
- BeanFacotry延遲加載,如果Bean的某一個(gè)屬性沒(méi)有注入,BeanFacotry加載后,直至第一次使用調(diào)用getBean方法才會(huì)拋出異常;而ApplicationContext則在初始化自身是檢驗(yàn),這樣有利于檢查所依賴(lài)屬性是否注入;所以通常情況下我們選擇使用 ApplicationContext。 應(yīng)用上下文則會(huì)在上下文啟動(dòng)后預(yù)載入所有的單實(shí)例Bean。通過(guò)預(yù)載入單實(shí)例bean ,確保當(dāng)你需要的時(shí)候,你就不用等待,因?yàn)樗鼈円呀?jīng)創(chuàng)建好了。
- BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區(qū)別是:BeanFactory需要手動(dòng)注冊(cè),而ApplicationContext則是自動(dòng)注冊(cè)。(Applicationcontext比 beanFactory 加入了一些更好使用的功能。而且 beanFactory 的許多功能需要通過(guò)編程實(shí)現(xiàn)而 Applicationcontext 可以通過(guò)配置實(shí)現(xiàn)。比如后處理 bean , Applicationcontext 直接配置在配置文件即可而 beanFactory 這要在代碼中顯示的寫(xiě)出來(lái)才可以被容器識(shí)別。 )
- beanFactory主要是面對(duì)的是 spring 框架的基礎(chǔ)設(shè)施,面對(duì) spring 自己。而 Applicationcontex 主要面對(duì)的是使用 spring 構(gòu)建項(xiàng)目的開(kāi)發(fā)人員。
到此這篇關(guān)于Spring中的ApplicationContext與BeanFactory詳解的文章就介紹到這了,更多相關(guān)ApplicationContext與BeanFactory內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring中的之啟動(dòng)過(guò)程obtainFreshBeanFactory詳解
- Spring中的BeanFactory與FactoryBean區(qū)別詳解
- Spring中的BeanFactory工廠(chǎng)詳細(xì)解析
- Spring中的BeanFactory對(duì)象實(shí)例化工廠(chǎng)詳解
- Spring中的FactoryBean與BeanFactory詳細(xì)解析
- Spring?BeanFactory容器的構(gòu)建和使用示例詳解
- Spring?BeanFactory工廠(chǎng)使用教程
- Spring中BeanFactory接口的作用小結(jié)
相關(guān)文章
SpringCloud OpenFeign 自定義響應(yīng)解碼器的問(wèn)題記錄
我們?cè)谑褂?nbsp;Spring Cloud 微服務(wù)的時(shí)候,通常將返回結(jié)果使用一個(gè)JsonResult 類(lèi)進(jìn)行封裝,本文重點(diǎn)介紹SpringCloud OpenFeign 自定義響應(yīng)解碼器的問(wèn)題記錄,感興趣的朋友跟隨小編一起看看吧2024-06-06
Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之棧和隊(duì)列
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之棧和隊(duì)列,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有一定的幫助,需要的朋友可以參考下2021-05-05
Java Class 解析器實(shí)現(xiàn)方法示例
這篇文章主要通過(guò)對(duì)class文件的分析,介紹了Java Class 解析器實(shí)現(xiàn)方法示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-09-09
MybatisPlus多表查詢(xún)及分頁(yè)查詢(xún)完整代碼
這篇文章主要介紹了MybatisPlus多表查詢(xún)及分頁(yè)查詢(xún)完整代碼,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
教你用Java GUI實(shí)現(xiàn)文本文件的讀寫(xiě)
今天帶大家來(lái)學(xué)習(xí)怎么用JavaSwing實(shí)現(xiàn)實(shí)現(xiàn)文本文件讀寫(xiě),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05
一篇文章教你使用枚舉來(lái)實(shí)現(xiàn)java單例模式
本篇文章主要介紹了Java實(shí)現(xiàn)單例的3種普遍的模式,餓漢式、懶漢式、枚舉式。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助2021-07-07

