BeanFactory 和ApplicationContext(Bean工廠和應用上下文)

一、BeanFactory 和ApplicationContext
Bean 工廠(com.springframework.beans.factory.BeanFactory)是Spring 框架最核心的接口,它提供了高級IoC 的配置機制。
應用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory 基礎之上。
幾乎所有的應用場合我們都直接使用ApplicationContext 而非底層的BeanFactory。

1.1 BeanFactory 的類體系結構

BeanFactory 接口位於類結構樹的頂端, 它最主要的方法就是getBean(StringbeanName),該方法從容器中返回特定名稱的Bean,BeanFactory 的功能通過其他的接口得到不斷擴展。
    ListableBeanFactory:該接口定義了訪問容器中Bean 基本信息的若干方法,如查看Bean 的個數、獲取某一類型Bean 的配置名、查看容器中是否包括某一Bean 等方法;
    HierarchicalBeanFactory:父子級聯IoC 容器的接口,子容器可以通過接口方法訪問父容器;
    ConfigurableBeanFactory:是一個重要的接口,增強了IoC 容器的可定製性,它定義了設置類裝載器、屬性編輯器、容器初始化後置處理器等方法;
    AutowireCapableBeanFactory:定義了將容器中的Bean 按某種規則(如按名字匹配、按類型匹配等)進行自動裝配的方法;
    SingletonBeanRegistry:定義了允許在運行期間向容器註冊單實例Bean 的方法;
    BeanDefinitionRegistry:Spring 配置文件中每一個<bean>節點元素在Spring 容器裏都通過一個BeanDefinition 對象表示,它描述了Bean 的配置信息。而BeanDefinitionRegistry 接口提供了向容器手工註冊BeanDefinition 對象的方法。

 

1.2 ApplicationContext 的類體系結構

ApplicationContext由BeanFactory 派生而來,提供了更多面向實際應用的功能。在BeanFactory 中,很多功能需要以編程的方式實現,而在ApplicationContext 中則可以通過配置的方式實現。
    ApplicationContext 的主要實現類是ClassPathXmlApplicationContext 和FileSystemXmlApplicationContext,前者默認從類路徑加載配置文件,後者默認從文件系統中裝載配置文件。

核心接口包括:
    ApplicationEventPublisher:讓容器擁有發佈應用上下文事件的功能,包括容器啓動事件、關閉事件等。實現了ApplicationListener 事件監聽接口的Bean 可以接收到容器事件, 並對事件進行響應處理。在ApplicationContext 抽象實現類AbstractApplicationContext 中,我們可以發現存在一個ApplicationEventMulticaster,它負責保存所有監聽器,以便在容器產生上下文事件時通知這些事件監聽者。
    MessageSource:爲應用提供i18n 國際化消息訪問的功能;
    ResourcePatternResolver : 所有ApplicationContext 實現類都實現了類似於
PathMatchingResourcePatternResolver 的功能,可以通過帶前綴的Ant 風格的資源文
件路徑裝載Spring 的配置文件。
    LifeCycle:該接口是Spring 2.0 加入的,該接口提供了start()和stop()兩個方法,主要用於控制異步處理過程。在具體使用時,該接口同時被ApplicationContext 實現及具體Bean 實現,ApplicationContext 會將start/stop 的信息傳遞給容器中所有實現了該接口的Bean,以達到管理和控制JMX、任務調度等目的。
    ConfigurableApplicationContext 擴展於ApplicationContext,它新增加了兩個主要的方法:refresh()和close(),讓ApplicationContext 具有啓動、刷新和關閉應用上下文的能力。在應用上下文關閉的情況下調用refresh()即可啓動應用上下文,在已經啓動的狀態下,調用refresh()則清除緩存並重新裝載配置信息,而調用close()則可關閉應用上下文。這些接口方法爲容器的控制管理帶來了便利

 

代碼示例:
ApplicationContext ctx =new ClassPathXmlApplicationContext("com/baobaotao/context/beans.xml");

ApplicationContext ctx =new FileSystemXmlApplicationContext("com/baobaotao/context/beans.xml");

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"conf/beans1.xml","conf/beans2.xml"});

    ApplicationContext 的初始化和BeanFactory 有一個重大的區別:BeanFactory在初始化容器時,並未實例化Bean,直到第一次訪問某個Bean 時才實例目標Bean;而ApplicationContext 則在初始化應用上下文時就實例化所有單實例的Bean 。

 

 

 

二、WebApplicationContext 類體系結構
    WebApplicationContext 是專門爲Web 應用準備的,它允許從相對於Web 根目錄的路徑中裝載配置文件完成初始化工作。從WebApplicationContext 中可以獲得ServletContext 的引用,整個Web 應用上下文對象將作爲屬性放置到ServletContext 中,以便Web 應用環境可以訪問Spring 應用上下文(ApplicationContext)。Spring 專門爲此提供一個工具類WebApplicationContextUtils,通過該類的getWebApplicationContext(ServletContext sc)方法,即可以從ServletContext 中獲取WebApplicationContext 實例。
    Spring 2.0 在WebApplicationContext 中還爲Bean 添加了三個新的作用域:request 作用域、session 作用域和global session 作用域。而在非Web 應用的環境下,Bean 只有singleton和prototype 兩種作用域。


    由於 Web 應用比一般的應用擁有更多的特性,因此WebApplicationContext 擴展了ApplicationContext。WebApplicationContext 定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文啓動時,WebApplicationContext 實例即以此爲鍵放置在ServletContext 的屬性列表中,因此我們可以直接通過以下語句從Web 容器中獲取
WebApplicationContext:
WebApplicationContext wac = (WebApplicationContext)servletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);


2.1 WebApplicationContext 的初啓動方式和BeanFactory、ApplicationContext 有所區別。
    因爲WebApplicationContext 需要ServletContext 實例,也就是說它必須在擁有Web 容器的前提下才能完成啓動的工作。有過Web 開發經驗的讀者都知道可以在web.xml 中配置自啓
動的Servlet 或定義Web 容器監聽器(ServletContextListener),藉助這兩者中的任何一個,我們就可以完成啓動Spring Web 應用上下文的工作。
    Spring 分別提供了用於啓動WebApplicationContext 的Servlet 和Web 容器監聽器:
   org.springframework.web.context.ContextLoaderServlet;
   org.springframework.web.context.ContextLoaderListener。
兩者的內部都實現了啓動WebApplicationContext 實例的邏輯,我們只要根據Web 容器的具體情況選擇兩者之一,並在web.xml 中完成配置就可以了。

2.2 下面是使用ContextLoaderListener 啓動WebApplicationContext 的具體配置:

Xml代碼

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/baobaotao-dao.xml, /WEB-INF/baobaotao-service.xml
    </param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener         </listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/baobaotao-dao.xml, /WEB-INF/baobaotao-service.xml </param-value>
</context-param>

2.3 如果在不支持容器監聽器的低版本Web 容器中,我們可採用ContextLoaderServlet 完成相同的工作:

Xml代碼


<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/baobaotao-dao.xml, /WEB-INF/baobaotao-service.xml </param-value>
</context-param>

<servlet>
    <servlet-name>springContextLoaderServlet</servlet-name>
    <servlet-class>org.springframework.web.context.ContextLoaderServlet         </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
三、WebApplicationContext 需要使用日誌功能

用戶可以將Log4J 的配置文件放置到類路徑WEB-INF/classes 下,這時Log4J 引擎即可順利啓動。

如果Log4J 配置文件放置在其他位置,用戶還必須在 web.xml 指定Log4J 配置文件位置。

Spring 爲啓用Log4J 引擎提供了兩個類似於啓動WebApplicationContext 的實現類:Log4jConfigServlet 和Log4jConfigListener,
不管採用哪種方式都必須保證能夠在裝載Spring 配置文件前先裝載Log4J 配置信息。

 

 

3.1 Log4jConfigServlet啓動日誌:

Xml代碼

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/baobaotao-dao.xml,/WEB-INF/baobaotao-service.xml
    </param-value>
</context-param>
<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<servlet>
    <servlet-name>log4jConfigServlet</servlet-name>
    <servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet>
    <servlet-name> springContextLoaderServlet</servlet-name>
    <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet> 

注意上面我們將log4jConfigServlet 的啓動順序號設置爲1,而springContextLoaderServlet的順序號設置爲2。這樣,前者將先啓動,完成裝載Log4J 配置文件初始化Log4J 引擎的工作,緊接着後者再啓動。如果使用Web 監聽器,則必須將Log4jConfigListener 放置在ContextLoaderListener 的前面。

 

3.2 Log4jConfigListener啓動日誌:

Xml代碼

	<!-- Log4J 配置  -->
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/conf/log4j.properties</param-value>
	</context-param>

	<!-- Spring上下文配置 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/conf/spring/applicationContext.xml</param-value>
	</context-param>
	<!-- Log4J監聽器  -->
	<listener>
		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
	</listener>

	<!-- Spring監聽器  -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

四、父子容器
    通過 HierarchicalBeanFactory 接口,Spring 的IoC 容器可以建立父子層級關聯的容器
體系,子容器可以訪問父容器中的Bean,但父容器不能訪問子容器的Bean。在容器內,Bean 的id 必須是唯一的,但子容器可以擁有一個和父容器id 相同的Bean。父子容器層級體系增強了Spring 容器架構的擴展性和靈活性,因爲第三方可以通過編程的方式,爲一個已經存在的容器添加一個或多個特殊用途的子容器,以提供一些額外的功能。
    Spring 使用父子容器實現了很多功能,比如在Spring MVC 中,展現層Bean 位於一個子容器中,而業務層和持久層的Bean 位於父容器中。這樣,展現層Bean 就可以引用業務層和持久層的Bean,而業務層和持久層的Bean 則看不到展現層的Bean。


發佈了101 篇原創文章 · 獲贊 14 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章