文章目錄
- 1.Spring IOC容器的設計
- 2.BeanFactory和ApplicationContext的差別
- 3.BeanFactory容器的設計原理
- 4.BeanFactory的詳細介紹
- 5.ApplicationContext容器的設計原理
- 6.ApplicationContext的詳細介紹
- 7.ApplicationContext容器擴充功能詳解介紹
1.Spring IOC容器的設計
- 實作BeanFactory接口的簡單容器
- 實作ApplicationContext接口的進階容器

ApplicationContext是BeanFactory的子接口。BeanFactory是Spring IoC容器的最底層接口, 隻提供了IOC容器的基本功能, 給具體的IOC 容器的實作提供了規範, 主要負責配置, 生産和管理Bean。内部定義了對單個bean的擷取,對bean的作用域判斷,擷取bean類型,擷取bean别名等功能。
而ApplicationContext繼承了MessageSource、ListableBeanFactory、ResourceLoader、ApplicationEventPublisher等接口。是進階的BeanFactory。進階容器
上面兩個重要的類都是接口,既然是接口那總得有具體的實作類。DefaultListableBeanFactory. 實作了包含所有Spring IOC 容器的基本功能。真正可以作為一個可以獨立使用的IOC容器還是DefaultListableBeanFactory, 而不是BeanFactory。所有DefaultListenerBeanFactory是Ioc容器的始祖。
2.BeanFactory和ApplicationContext的差別
BeanFactory和ApplicationContext是Spring IOC容器的兩大核心接口。ApplicationContext是BeanFactory的子接口。
①、提供的功能不同:
BeanFactory提供了Bean的定義,讀取bean配置文檔,管理bean的加載、執行個體化,控制bean的生命周期,維護bean之間的依賴關系等。
public interface ApplicationContext extends
EnvironmentCapable,
ListableBeanFactory,
HierarchicalBeanFactory,
MessageSource,
ApplicationEventPublisher,
ResourcePatternResolver {
}
- 支援國際化(MessageSource)
- 統一的資源檔案通路方式(ResourcePatternResolver)
- 提供在監聽器中注冊bean的事件(ApplicationEventPublisher)
- 同時加載多個配置檔案
- 載入多個(有繼承關系)上下文 ,使得每一個上下文都專注于一個特定的層次,比如應用的web層(HierarchicalBeanFactory)
②、 啟動時的狀态不同:
BeanFactroy采用的是延遲加載形式來注入Bean的,使用的時候對Bean執行個體化, 不存在Spring的配置問題, 如果一個Bean的屬性未注入, BeanFactory加載後, 直到第一次調用getBean()的時候才會抛出異常。
ApplicationContext:啟動的時候, 創所有的Bean, 這樣, 容器啟動的時候, 發現配置錯誤的話, 有利于檢查依賴是否注入。相對于基本的BeanFactory,ApplicationContext 唯一的不足是占用記憶體空間。當應用程式配置Bean較多時,程式啟動較慢。
③、BeanFactory通常以程式設計的方式被建立,ApplicationContext還能以聲明的方式建立,如使用ContextLoader。
④、BeanFactory和ApplicationContext都支援BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的差別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊。
3.BeanFactory容器的設計原理
- HierarchicalBeanFactory:提供父容器的通路功能,它内部定義了兩個方法。
- ListableBeanFactory:提供了列出工廠中所有的Bean的方法 定義了容器内Bean的枚舉功能(枚舉出來的Bean不會包含父容器)。
- AutowireCapableBeanFactory:在BeanFactory基礎上實作對已存在執行個體的管理,主要定義了內建其它架構的功能。一般應用開發者不會使用這個接口,是以像ApplicationContext這樣的外觀實作類不會實作這個接口,如果真想用可以通過ApplicationContext的getAutowireCapableBeanFactory接口擷取。
- ConfigurableBeanFactory:定義了BeanFactory的配置功能。
- ConfigurableListableBeanFactory:繼承了上述的所有接口,增加了其他功能:比如類加載器、類型轉化、屬性編。
- BeanPostProcessor、作用域、bean定義、處理bean依賴關系、bean如何銷毀等功能。
- DefaultListableBeanFactory:實作上述BeanFactory接口中所有功能。它還可以注冊BeanDefinition。
- XmlBeanFactory :在Spring3.1之前使用,後面被标記為Deprecated,繼承自DefaultListableBeanFactory,增加了對Xml檔案解析的支援。
XmlBeanFactory是BeanFactory體系中的最底層的實作類。XmlBeanFactory在父類的基礎上增加了對XML檔案解析的支援,也就是說它是一個可以讀取XML檔案方式定義BeanDefinition的IOC容器。
BeanDefination: 它是對 IOC容器中管理的對象依賴關系的資料抽象。控制反轉功能都是圍繞對這個BeanDefinition的處理來完成的。
BeanDefinition在Spring中是用來描述Bean對象的,它本身并不是一個Bean執行個體,而是包含了Bean執行個體的所有資訊,比如類名、屬性值、構造器參數、scope、依賴的bean、是否是單例類、是否是懶加載以及其它資訊。其實就是将Bean執行個體定義的資訊存儲到這個BeanDefinition相應的屬性中,後面Bean對象的建立是根據BeanDefinition中描述的資訊來建立的,例如拿到這個BeanDefinition後,可以根據裡面的類名、構造函數、構造函數參數,使用反射進行對象建立。也就是說 IOC容器可以有多個BeanDefinition,并且一個BeanDefinition對象對應一個标簽中的資訊。
當然BeanDefinition的最終目的不隻是用來存儲Bean執行個體的所有資訊,而是為了可以友善的進行修改屬性值和其他元資訊,比如通過BeanFactoryPostProcessor進行修改一些資訊,然後在建立Bean對象的時候就可以結合原始資訊和修改後的資訊建立對象了。
XmlBeanFactory:
@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
初始化了一個 XmlBeanDefinitionReader對象, 目的是讀取xml檔案, 将Bean的xml配置檔案轉化為多個BeanDefinition工具類, 一個BeanDefination對象對應一個标簽的資訊。
執行loadBeanDefinition()方法: 加載BeanDefination的操作,
4.BeanFactory的詳細介紹
5個擷取執行個體的方法(getBean的重載方法);2個擷取Bean的提供者;4個判斷的方法(判斷是否存在,是否為單例、原型,名稱類型是否比對);2個擷取類型的方法和1個擷取别名的方法。
public interface BeanFactory {
//使用者使用容器時,可以使用轉義符“&”來得到FactoryBean本身
String FACTORY_BEAN_PREFIX = "&";
//擷取Bean
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
T getBean(Class requiredType) throws BeansException;
T getBean(Class requiredType, Object... args) throws BeansException;
//擷取bean的提供者(對象工廠)
ObjectProvider getBeanProvider(Class requiredType);
ObjectProvider getBeanProvider(ResolvableType requiredType);
//判斷是否包含指定名字的bean
boolean containsBean(String name);
//擷取指定名字的Bean是否是Singleton類型的Bean,對于Singleton屬性,使用者可以在BeanDefinition中指定
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//擷取指定名字的Bean是否是Prototype類型的,與Singleton屬性一樣也可以在BeanDefinition中指定
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//指定名字的bean是否和指定的類型比對
boolean isTypeMatch(String name, ResolvableType typeToMatch);
boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException;
//擷取指定名字的Bean的Class類型
Class getType(String name) throws NoSuchBeanDefinitionException;
//擷取指定名字的Bean的所有别名,這些别名是使用者在BeanDefinition中定義的
String[] getAliases(String name);
}
-
getBean部分(重要):該方法表示擷取bean執行個體
①、根據名字擷取bean:getBean(String name)
②、根據類型擷取bean:getBean(Class requiredType)
③、根據名字和類型擷取bean(推薦):getBean(String name, Class requiredType)
④、根據名稱、類型和給定的構造函數參數或者工廠方法參數構造對象擷取bean
- getBeanProvider部分:該方法表示擷取bean的提供者(對象工廠)
-
containsBean(String name):通過名字判斷是否包含指定bean的定義 。
isSingleton(String name) isPrototype(String name):判斷是單例和原型(多例)的方法。
isTypeMatch:判斷給定bean的名字是否和類型比對 。
getType(String name):根據bean的名字來擷取其類型的方法 (按 Java 類型比對的方式 )。
getAliases(String name):根據bean的名字來擷取其别名的方法。
-
ResolvableType參數介紹
ResolvableType是對Java java.lang.reflect.Type的封裝,并且提供了一些通路該類型的其他資訊的方法(例如父類, 泛型參數,該類)。從成員變量、方法參數、方法傳回類型、類來建構ResolvableType的執行個體。
5.ApplicationContext容器的設計原理
ClassPathXmlApplicationContext:
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
configLocation表示的是Spring配置檔案的路徑
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 1.初始化父類
super(parent);
// 2.設定本地的配置資訊
setConfigLocations(configLocations);
// 3.完成Spring IOC容器的初始化
if (refresh) {
refresh();
}
}
首先初始化了父類,就是一直到父類AbstractApplicationContext中,将ApplicationContext的環境屬性設定給本類的環境屬性,包括一些profile,系統屬性等。
然後設定本地的配置檔案資訊,這裡調用其父類AbstractRefreshableConfigApplicationContext 的 setConfigLocations 方法,該方法主要處理ClassPathXmlApplicationContext傳入的字元串中的占位符,即解析給定的路徑數組(這裡就一個),setConfigLocations 方法源碼如下:
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//循環取出每一個path參數,在此處就一個applicationContext.xml
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
setConfigLocations方法除了處理ClassPathXmlApplicationContext傳入的字元串中的占位符之外,其實還有一個作用:建立環境對象ConfigurableEnvironment。
refresh():
進階容器的所有功能(包括 IoC)
//AbstractApplicationContext.refresh()方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//重新整理上下文環境
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//這裡是在子類中啟動 refreshBeanFactory() 的地方,獲得新的BeanFactory,解析XML、Java類,并加載BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//準備bean工廠,以便在此上下文中使用
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//設定 beanFactory 的後置處理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//調用 BeanFactory 的後處理器,這些處理器是在Bean 定義中向容器注冊的
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注冊Bean的後處理器,在Bean建立過程中調用
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//對上下文中的消息源進行初始化
initMessageSource();
// Initialize event multicaster for this context.
//初始化上下文中的事件機制
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//初始化其他特殊的Bean
onRefresh();
// Check for listener beans and register them.
//檢查監聽Bean并且将這些監聽Bean向容器注冊
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//執行個體化所有的(non-lazy-init)單件
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//釋出容器事件,結束Refresh過程
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
//重置Spring公共的緩存
resetCommonCaches();
}
}
}
- prepareRefresh() :為重新整理準備上下文,主要設定狀态量(是否關閉,是否激活),記錄啟動時間,初始化屬性資源占位符、校驗必填屬性是否配置及初始化用于存儲早期應用事件的容器。
- obtainFreshBeanFactory():主要用于擷取一個新的BeanFactory,如果BeanFactory已存在,則将其銷毀并重建,預設重建的BeanFactory為AbstractRefreshableApplicationContext;此外此方法委托其子類從XML中或基于注解的類中加載BeanDefinition。
- prepareBeanFactory():配置BeanFactory使其具有一個上下文的标準特征,如上下文的類加載器、後處理程式(post-processors,如設定如總感覺接口)。
- postprocessBeanFactory():在應用上下文内部的BeanFactory初始化結束後對其進行修改,在所有的BeanDefinition已被加載但還沒有執行個體化bean, 此刻可以注冊一些特殊的BeanPostFactory,如web應用會注冊ServletContextAwareProcessor等。
- invokeBeanFactoryPostProcessors():調用注冊在上下文中的BeanFactoryPostProcessor,如果有順序則按順序調用,并且一定再單列對象執行個體化之前調用。
- registerBeanPostProcessors():執行個體化并注冊BeanPostProcessor,如果有顯式的順序則按照順序調用一定在所有bean執行個體化之前調用。
- initMessageSource():初始化MessageSource,如果目前上下文沒有定義則使用其父類的,如果BeanFactory中不能找到名稱為messageSource中的bean, 則預設使用DelegatingMessageSource。
- initApplicationEventMulticaster():初始化ApplicationEventMulticaster,如果上下文沒有定義則預設使用 - SimpleApplicationEventMulticaster,此類主要用于廣播ApplicationEvent。
- onRefresh() :在一些特定的上下文子類中初始化特定的bean,如在Webapp的上下文中初始化主題資源。
- registerListeners():添加實作了ApplicationListener的bean作為監聽器,它不影響非bean的監聽器;還會使用多點傳播器釋出早期的ApplicationEvent。
- finishBeanFactoryInitialization():執行個體化所有非延遲加載的單例,完成BeanFactory的初始化工作。
- finishRefresh():完成上下文的重新整理工作,調用LifecycleProcessor的onFresh()及釋出的ContextRefreshEvent事件。
- resetCommonCaches():重置Spring公共的緩存,如:ReflectionUtils、ResolvableType、CachedIntrospectionResults的緩存CachedIntrospectionResults的緩存。
14個方法
6.ApplicationContext的詳細介紹
(1)、ClassPathXmlApplicationContext:從系統類路徑classpath下加載一個或多個xml配置檔案,找到并裝載完成ApplicationContext的執行個體化工作。例如:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
(2)、FileSystemXmlApplicationContext:從系統磁盤下加載一個或多個xml配置檔案(必須有通路權限)。也就是讀取系統磁盤指定路徑的xml檔案。例如:
ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");
它與ClassPathXmlApplicationContext的差別在于讀取Spring配置檔案的方式,FileSystemXmlApplicationContext不在從類路徑下讀取配置檔案,而是通過制定參數從系統磁盤讀取,前提是有通路權限。
(3)、XmlWebApplicationContext:從web應用下加載一個或多個xml配置檔案,适用于web應用的xml配置方式。
在Java項目中提供ClassPathXmlApplicationContext類手工執行個體化ApplicationContext容器通常是不二之選,但是對于Web項目就不行了,Web項目的啟動是由相應的Web伺服器負責的,是以,在Web項目中ApplicationContext容器的執行個體化工作最好交由Web伺服器來完成。Spring為此提供了以下兩種方式:
- org.springframework.web.context.ContextLoaderListener
- org.springframework.web.context.ContexLoaderServlet(此方法目前以廢棄)
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
@WebServlet("/MyServlet")
public class MyServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//建立XmlWebApplicationContext對象,但這時并沒有初始化容器
XmlWebApplicationContext context = new XmlWebApplicationContext();
// 指定配置檔案路徑
context.setConfigLocation("application.xml");
// 需要指定ServletContext對象
context.setServletContext(request.getServletContext());
// 初始化容器
context.refresh();
//擷取執行個體
Additive additive = (Additive) context.getBean("additive");
additive.addAdditive();
}
}
(4)、AnnotationConfigApplicationContext:從Java注解的配置類中加載Spring的ApplicationContext容器。使用注解避免使用application.xml進行配置。相比XML配置,更加便捷。
@Configuration
public class AppConfig {
@Bean(name = "orangeJuice")
public OrangeJuice orangeJuice(){
OrangeJuice orangeJuice = new OrangeJuice();
return orangeJuice;
}
@Bean(name = "additive")
public Additive additive(){
Additive additive = new Additive();
return additive;
}
}
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
com.thr.AppConfig
org.springframework.web.context.ContextLoaderListener