??通過一個配置文件描述Bean及Bean之間的依賴關(guān)系王滤,利用Java語言的反射功能實例化Bean并建立Bean之間的依賴關(guān)系敛苇。Sping的IoC容器在完成這些底層工作的基礎(chǔ)上,還提供了Bean實例緩存抄邀,生命周期管理暗赶,Bean實例代理,事件發(fā)布,資源裝載等高級服務(wù)夯辖。
??Bean工廠(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口琉预,它提供了高級IoC的配置機制。BeanFactory使管理不同類型的Java對象成為可能蒿褂,應(yīng)用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory基礎(chǔ)之上娩井,提供了更多面向應(yīng)用的功能毕泌,它提供了國際化支持和框架事件體系激率,更易于創(chuàng)建實際應(yīng)用。我們一般稱BeanFactory為IoC容器也祠,而稱ApplicationContext為應(yīng)用上下文。但有時為了行文方便近速。
我們可以進行簡單劃分:
BeanFactory是Sping框架的基礎(chǔ)設(shè)施诈嘿,而面向sping本身;ApplicationContext面向使用Sping框架的開發(fā)者削葱,幾乎所有的應(yīng)用場合我們都是直接使用ApplicationContet而非底層的BeanFactory奖亚。
BeanFactory介紹
??誠如其名,BeanFactory是一個類工廠析砸,但和傳統(tǒng)的類工廠不同昔字,傳統(tǒng)的類工廠僅負責(zé)構(gòu)造一個或幾個類的實例。而BeanFactory是類的通用工廠首繁,它可以創(chuàng)建并管理各種類的對象作郭。這些可被創(chuàng)建和管理的對象本身沒有什么特別之處,僅是一個POJO弦疮。Sping稱這些被創(chuàng)建和管理的Java對象為Bean夹攒。我們知道JavaBean是要滿足一定規(guī)范的,如必須提供一個默認不帶參的構(gòu)造函數(shù)挂捅,不依賴于某一特定的容器等芹助,但Spring中所說的Bean比JavaBean更寬泛一些,所有可以被Sping容器實例化并管理的Java類都可以成為Bean闲先。
BeanFactory的類體系結(jié)構(gòu)
??Spring為BeanFactory提供了多種實現(xiàn)状土,最常用的是XmlBeanFactory。XmlBeanFactory的類繼承體系設(shè)計優(yōu)雅伺糠,堪稱經(jīng)典蒙谓。通過繼承體系,我們可以很容易了解到XmlBeanFactory具有哪些功能:??BeanFactory接口位于類結(jié)構(gòu)樹的頂端训桶,它最主要的方法就是getBean(String beanName),該方法從容器中返回特定名稱的Bean,BeanFactory的功能通過其他的接口得到不斷擴展累驮。下面對上圖涉及到的其他接口分別進行說明。
- ListableBeanFactory:該接口定義了訪問容器中Bean基本信息的若干方法舵揭,如查看Bean的個數(shù)谤专,獲取某一個類型Bean的配置名,查看容器中是否包括某一Bean等方法午绳;
- HierarchicalBeanFactory:父子級聯(lián)IoC容器的接口置侍,子容器可以通過接口方法訪問父容器;
- ConfigurableBeanFactory:是一個重要的接口,增強了IoC容器的可定制性蜡坊,它定義了設(shè)置類裝載器杠输,屬性編輯器,容器初始化后置處理器等方法秕衙;
- AutowireCapableBeanFactory;
初始化BeanFactory
??下面蠢甲,我們使用sping配置文件為Car提供配置信息,然后通過BeanFactory裝在配置文件据忘,啟動sping IoC容器鹦牛。sping配置文件如下:
<?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-3.0.xsd">
<bean id="car" class="com.hhxs.bbt.web.Car"
p:brand="紅旗CA72"
p:color="黑色"
p:maxSpeed="200" />
</beans>
下面我們通過XmlBeanFactory實現(xiàn)類啟動sping IoC容器:
public class BeanFactoryTest {
public static void main(String[] args) throws Throwable{
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource res = resolver.getResource("classpath:spring/beans.xml");
System.out.println(res.getURL());
BeanFactory bf = new XmlBeanFactory(res);
System.out.println("init BeanFactory.");
Car car = bf.getBean("car",Car.class);
System.out.println("car bean is ready for use!");
car.introduce();
}
}
??XmlBeanFactory通過Resource裝裝載sping配置信息并啟動IoC容器,然后就可以通過BeanFactory#getBean(beanName)方法從IoC容器中獲取Bean了若河。通過BeanFactory啟動IoC容器時能岩,并不會初始化配置文件中定義的Bean,初始化動作發(fā)生在第一個調(diào)用時萧福。對于單實例(singleton)的Bean來說拉鹃,BeanFactory會緩存Bean實例,所以第二次使用getBean()獲取Bean時將直接從IoC容器的緩存中獲取Bean實例鲫忍。
??sping在DefaultSingletonBeanRegistry類中提供了一個用于緩存單實例Bean的緩存器膏燕,它是一個用HashMap實現(xiàn)的緩存器,單實例的Bean以beanName為鍵保存在這個HashMap中悟民。
??值得一提的是坝辫,在初始化BeanFactory時,必須為其提供一種日志框架射亏,我們使用Log4J,即在類路徑下提供Log4J配置文件近忙,這樣啟動Sping容器才不會報錯。
ApplicationContext介紹
??如果說BeanFactory是Sping的心臟智润,那么ApplicationContext就是完整的身軀了及舍。ApplicationContext由BeanFactory派生而來,提供了更多面向?qū)嶋H應(yīng)用的功能窟绷。在Beanfactory中锯玛,很多功能需要以編程的方式實現(xiàn),而在ApplicationContext中則可以通過配置的方式實現(xiàn)兼蜈。
ApplicationContext類體系結(jié)構(gòu)
??ApplicationContext的主要實現(xiàn)類是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext攘残,前者默認從類路徑加載配置文件,后者默認從文件系統(tǒng)中裝載配置文件为狸,我們了解一下ApplicationContext的類繼承體系:
??從上圖中我們可以看出ApplicationContext繼承了hierarchicalBeanFactory和ListableBeanFactory接口歼郭,在此基礎(chǔ)上,還通過多個其他的接口擴展了BeanFactory的功能辐棒,這些接口包括:
- ApplicationEventPublisher:讓容器擁有發(fā)布應(yīng)用上下文事件的功能病曾,包括容器啟動事件姊途,關(guān)閉事件等。實現(xiàn)了ApplicationListener事件監(jiān)聽接口的Bean可以接收到容器事件知态,并對事件進行響應(yīng)處理。在ApplicationContext抽象實現(xiàn)類AbstractApplicationContext中立叛,我們可以發(fā)現(xiàn)存在一個ApplicationEventMulticaster负敏,它負責(zé)保存所有監(jiān)聽器,以便在容器產(chǎn)生上下文事件時通知這些事件監(jiān)聽者秘蛇。
- MessageSource:為應(yīng)用提供i18n國際化消息訪問的功能其做;
- ResourcePatternResolver:所有ApplicationContext實現(xiàn)類都實現(xiàn)了類似于PathMatchingResourcePatternResolver的功能,可以通過帶前綴的Ant風(fēng)格的資源文件路徑裝載sping的配置文件赁还。
- LifeCycle:該接口是Sping2.0加入的妖泄,該接口提供了start()和stop()兩個方法,主要用于控制異步處理過程艘策。在具體使用時蹈胡,ApplicationContext及具體的Bean都必須同時該接口,ApplicationContext會將start/stop的信息傳遞給容器中所有實現(xiàn)了該接口的Bean朋蔫,已達到管理和控制JMX,任務(wù)調(diào)度等目的罚渐。
??在獲取ApplicationContext實例后,就可以像BeanFactory一樣調(diào)用getBean(beanName)返回Bean了驯妄。ApplicationContext的初始化和BeanFactory有一個重大的區(qū)別:BeanFactory在初始化容器時荷并,并未實例化Bean,直到第一次訪問某個Bean時才實例化目標Bean;而ApplicationContext則在初始化應(yīng)用上下文時就實例化所有單實例的Bean青扔。因此ApplicationContext的初始化時間會比BeanFactory稍長一些源织,不過稍后的調(diào)用則沒有“第一次懲罰”問題。
??spring3.0支持基于類注解的配置方式微猖,主要功能來自于sping的名為JavaConfig子項目谈息,目前JavaConfig已經(jīng)升級為spring核心框架的一部分。一個標注@Configuration注解的POJO即可提供sping所需的Bean配置信息:
package com.yeren;
public class Car {
private String brand;
private String color;
private int maxSpeed;
public Car(){}
public Car(String brand,String color,int maxSpeed){
this.brand=brand;
this.color=color;
this.maxSpeed=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 void introduce(){
System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed);
}
}
package com.yeren;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.awt.*;
@Configuration
public class BeanA {
@Bean(name="car")
public Car buildCar(){
Car car=new Car();
car.setBrand("紅旗CA72");
car.setMaxSpeed(200);
return car;
}
}
package com.yeren;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* Hello world!
*
*/
public class App
{
public static void main(String []args)throws Throwable{
ApplicationContext ctx=new AnnotationConfigApplicationContext(BeanA.class);
Car car=ctx.getBean("car",Car.class);
System.out.println();
}
}
??和基于XML文件配置方式的優(yōu)勢在于励两,類注解的配置方式可以很容易地讓開發(fā)者控制Bean的初始化過程黎茎,比基于XML的配置更加靈活。sping為基于注解類的配置提供了專門的ApplicationContext實現(xiàn)類:AnnotationConfigApplicationContext当悔。
WebApplicationContext類體系結(jié)構(gòu)
WebApplicationContext是專門為Web應(yīng)用準備的傅瞻,它允許從相對于Web根目錄的路徑中裝載配置文件完成初始化工作。從WebApplicationContext中可以獲得ServletContextde引用盲憎,整個Web應(yīng)用上下文對象將作為屬性放置到ServletContext中嗅骄,以便Web應(yīng)用環(huán)境可以訪問Sping應(yīng)用上下文。sping專門為此提供一個工具類WebApplicationContextUtils饼疙,通過該類的getWebApplicationContext(ServletContext sc)方法溺森,即可以從ServletContext中獲取WebApplicationContext實例慕爬。
??由于Web應(yīng)用比一般的應(yīng)用擁有更多的特性,因此WebApplicationContext擴展了ApplicationContext屏积。WebApplicationContext定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文啟動時医窿,WebApplicationContext實例即以此為鍵放置在ServletContext的屬性列表中,因此我們可以直接通過以下話語從Web容器中獲取WebApplicationContext:
WebApplicationContext wac=(WebApplicationContext)servletContext.getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
這正是我們前面提到的WebApplicationContextUtils工具類getWebApplicationContext(ServletContext sc)方法的內(nèi)部實現(xiàn)方式炊林。這樣sping的web應(yīng)用上下文和web容器的上下文就可以實現(xiàn)互訪姥卢,二者實現(xiàn)了融合:
??ConfigurableWebApplicationContext擴展了WebApplicationContext,它允許通過配置的方式實例化WebaApplicationContext渣聚,它定義了兩個重要的方法:
- setServletContext(ServletContext servletContext):為sping設(shè)置web應(yīng)用上下文独榴,以便兩者整合;
- setConfigLocations(String[] configLocations):設(shè)置sping配置文件地址奕枝,一般情況下棺榔,配置文件地址是相對于web根目錄的地址,如/WEB-INF/baobaotao-dao.xml,/WEB-INF/baobaotao-service.xml等隘道。但用戶也可以使用帶資源類型前綴的地址症歇,如classpath:com/baobaotao/beans.xml等。
WebApplicationContext初始化
??WebApplicationContext的初始化方式和BeanFactory薄声,ApplicationContext有所區(qū)別当船,因為WebApplicationContext需要Servlet或定義Web容器監(jiān)聽器(ServletContextListener),借助這兩者中的任何一個,我們就可以完成啟動sping web應(yīng)用上下文的工作默辨。
??sping分別提供了用于啟動WebApplicationContext的Servlet和Web容器監(jiān)聽器: - org.spingframework.web.context.ContextLoaderServlet;
- org.spingframework.web.context.ContextLoaderListener德频。
??兩者的內(nèi)部都實現(xiàn)了啟動WebApplicationContext實例的邏輯,我們只要根據(jù)Web容器的具體情況選擇兩者之一缩幸,并在web.xml中完成配置就可以了壹置。
父子容器
??通過HierarchicalBeanFactory接口,sping的IoC容器可以建立父子層級關(guān)聯(lián)的容器體系表谊,子容器可以訪問父容器中的Bean钞护,但父容器不能訪問子容器的Bean。在容器內(nèi)爆办,Bean的id必須是唯一的难咕,但子容器可以擁有一個和父容器id相同的Bean。父子容器層級體系增強了sping容器架構(gòu)的擴展性和靈活性距辆,因為第三方可以通過編程的方式余佃,為一個已經(jīng)存在的容器添加一個或多個特殊用途的子容器,以提供一些額外的功能跨算。