Spring是一個輕量級的控制反轉(IoC)和麪向切面(AOP)的容器框架,如何在程序中獲取Spring配置的bean呢? java
Bean工廠(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高級IoC的配置機制。BeanFactory使管理不一樣類型的Java對象成爲可能,應用上下文(com.springframework.context.ApplicationContext)創建在BeanFactory基礎之上,提供了更多面嚮應用的功能,它提供了國際化支持和框架事件體系,更易於建立實際應用。咱們通常稱BeanFactory爲IoC容器,而稱ApplicationContext爲應用上下文。但有時爲了行文方便,咱們也將ApplicationContext稱爲Spring容器。
對於二者的用途,咱們能夠進行簡單劃分:BeanFactory是Spring框架的基礎設施,面向Spring自己;ApplicationContext面向使用Spring框架的開發者,幾乎全部的應用場合咱們都直接使用ApplicationContext而非底層的BeanFactory。 web
工廠方式:Resource resource = new ClassPathResource("/applicationContext.xml"); spring
BeanFactory factory = new XmlBeanFactory(resource); factory.getBean(strName);
ApplicationContext的初始化和BeanFactory有一個重大的區別:BeanFactory在初始化容器時,並未實例化Bean,直到第一次訪問某個Bean時才實例目標Bean;而ApplicationContext則在初始化應用上下文時就實例化全部單實例的Bean。所以ApplicationContext的初始化時間會比BeanFactory稍長一些 緩存
附加信息(有問題或者不一樣看法歡迎指點),簡要說明Spring何時實例化bean,首先要分2種狀況
第一:若是你使用BeanFactory做爲Spring Bean的工廠類,則全部的bean都是在第一次使用該Bean的時候實例化
第二:若是你使用ApplicationContext做爲Spring Bean的工廠類,則又分爲如下幾種狀況:
(1):若是bean的scope是singleton的,而且lazy-init爲false(默認是false,因此能夠不用設置),則 ApplicationContext啓動的時候就實例化該Bean,而且將實例化的Bean放在一個map結構的緩存中,下次再使用該Bean的時候, 直接從這個緩存中取
(2):若是bean的scope是singleton的,而且lazy-init爲true,則該Bean的實例化是在第一次使用該Bean的時候進行實例化
(3):若是bean的scope是prototype的,則該Bean的實例化是在第一次使用該Bean的時候進行實例化
session
本文不涉及經過@Resource 、@Autowired 自動注入,僅僅經過ApplicationContext獲取Sping配置文件中的Bean。 app
要獲取XML中配置的Bean,最關鍵的是獲取org.springframework.context.ApplicationContext 框架
第一種獲取ApplicationContext的方法: 工具
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationContext.xml");
或者
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
private ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
這種方式實例化applicationContext是很是耗時的,這種方式適用於採用Spring框架的獨立應用程序,僅僅推薦使用在程序須要經過配置文件手工初始化Spring的狀況。
ApplicationContext的主要實現類是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默認從類路徑加載配置文件,後者默認從文件系統中裝載配置文件 ui
例子: spa
public class BeanManager {
private static ApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml") ;
public static Object getBean(String beanId) {
return context.getBean(beanId);
}
}
在web.xml中寫一個servlet,自動啓動,init方法中調用一下BeanManager
init() throws ServletException {
BeanManager bm = new BeanManager();//可選的,爲的是在web應用啓動的時候就讓spring加載bean配置。
// 不然會在第一次調用BeanManager的時候加載,影響一次速度。
}
在java代碼中使用 BeanManager.getBean(String beanId); 來得到bean實例。
第二種獲取ApplicationContext的方法:經過Spring提供的工具類獲取ApplicationContext對象,專爲web工程定製的方法,推薦Web項目中使用。例如:
ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext ac1 = WebApplicationContextUtils .getRequiredWebApplicationContext(ServletContext sc)
ApplicationContext ac2 = WebApplicationContextUtils .getWebApplicationContext(ServletContext sc)
ac1.getBean("beanId");
ac2.getBean("beanId");
經過javax.servlet.ServletContext 獲取到ApplicationContext實例對象,這意味着,必須使用到request、session等等。
這樣,就不能把ApplicationContext對象設置爲成員變量。須要在每一個具體的方法中經過request、session等獲取到ServletContext再獲取ApplicationContext實例。
所以,此方法僅僅推薦使用在能夠獲取到ServletContext對象的Web項目中,而且不須要將ApplicationContext對象定義爲成員變量的狀況下。
注意:當使用WebApplicationContextUtils獲取ApplicationContext實例時,須要在web.xml配置文件中添加org.springframework.web.context.ContextLoaderListener監聽器,不然獲取不到ApplicationContext對象,返回Null。
配置文件:web.xml
<!--ContextLoaderListener自動注入 applicationContext,經過
WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext())獲取 -->
<!--Spring配置文件加載位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appContext.xml,/WEB-INF/spring/appInterceptor.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3. 繼承自抽象類ApplicationObjectSupport
抽象類ApplicationObjectSupport提供getApplicationContext()方法,能夠方便的獲取到ApplicationContext。Spring初始化時,會經過該抽象類的setApplicationContext(ApplicationContext context)方法將ApplicationContext 對象注入。
4. 繼承自抽象類WebApplicationObjectSupport
經過繼承org.springframework.web.context.support.WebApplicationObjectSupport使用getWebApplicationContext() 獲取到org.springframework.web.context.WebApplicationContext
因爲Web應用比通常的應用擁有更多的特性,所以WebApplicationContext擴展了ApplicationContext。WebApplicationContext定義了一個常量ROOT_WEB_APPLICATION_ CONTEXT_ATTRIBUTE,在上下文啓動時,WebApplicationContext實例即以此爲鍵放置在ServletContext的屬性列表中,所以咱們能夠直接經過如下語句從Web容器中獲取WebApplicationContext:
WebApplicationContext wac = (WebApplicationContext)servletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
5. 實現接口ApplicationContextAware
實現該接口的setApplicationContext(ApplicationContext context)方法,並保存ApplicationContext 對象。Spring初始化時,會經過該方法將ApplicationContext 對象注入。
public class SpringContextUtil implements ApplicationContextAware{//Spring的工具類,用來得到配置文件中的bean
private static ApplicationContext applicationContext = null;
/***
* 當繼承了ApplicationContextAware類以後,那麼程序在調用
* getBean(String)的時候會自動調用該方法,不用本身操做
*/
public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
}
第3、4、五種方法都須要將類配置在Spring配置文件中:
<!--假定ApplicationContextTool爲繼承或者實現了第3、4、五種方法的具體實現類-->
<bean class="com.twovv.utils.ApplicationContextTool"></bean>
不然將獲取不到ApplicationContext,返回Null。