1 BeanFactory解析
Spring中Bean的建立是典型的工廠模式,這一系列的Bean工廠,即IoC容器,為開發者管理物件之間的依賴關係提供了很多便利和基礎服務,在Spring中有許多IoC容器的實現供使用者選擇,其相互關係如下圖所示。
其中,BeanFactory作為最頂層的一個介面,定義了IoC容器的基本功能規範,BeanFactory有三個重要的子介面:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是從類圖中我們可以發現最終的預設實現類是DefaultListableBeanFactory,它實現了所有的介面。
那麼為何要定義這麼多層次的介面呢?
每個介面都有它的使用場合,主要是為了區分在Spring內部操作過程中物件的傳遞和轉化,對物件的資料訪問所做的限制。例如,
-
ListableBeanFactory介面表示這些Bean可列表化。
-
HierarchicalBeanFactory表示這些Bean 是有繼承關係的,也就是每個 Bean 可能有父 Bean
-
AutowireCapableBeanFactory 介面定義Bean的自動裝配規則。
這三個介面共同定義了Bean的集合、Bean之間的關係及Bean行為。最基本的IoC容器介面是BeanFactory,來看一下它的原始碼:
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
//根據bean的名稱獲取IOC容器中的的bean物件
Object getBean(String name) throws BeansException;
//根據bean的名稱獲取IOC容器中的的bean物件,並指定獲取到的bean物件的型別,這樣我們使用時就不需要進行型別強轉了
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
//判斷容器中是否包含指定名稱的bean物件
boolean containsBean(String name);
//根據bean的名稱判斷是否是單例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
在BeanFactory裡只對IoC容器的基本行為做了定義,根本不關心你的Bean是如何定義及怎樣載入的。正如我們只關心能從工廠裡得到什麼產品,不關心工廠是怎麼生產這些產品的。
BeanFactory有一個很重要的子介面,就是ApplicationContext介面,該介面主要來規範容器中的bean物件是非延時載入,即在建立容器物件的時候就物件bean進行初始化,並儲存到一個容器中。
要知道工廠是如何產生物件的,我們需要看具體的IoC容器實現,Spring提供了許多IoC容器實現,比如:
-
ClasspathXmlApplicationContext : 根據類路徑載入xml配置檔案,並建立IOC容器物件。
-
FileSystemXmlApplicationContext :根據系統路徑載入xml配置檔案,並建立IOC容器物件。
-
AnnotationConfigApplicationContext :載入註解類配置,並建立IOC容器。
2 BeanDefinition解析
Spring IoC容器管理我們定義的各種Bean物件及其相互關係,而Bean物件在Spring實現中是以BeanDefinition來描述的,如下面配置檔案
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
bean標籤還有很多屬性:
scope、init-method、destory-method等。
其繼承體系如下圖所示。
3 BeanDefinitionReader解析
Bean的解析過程非常複雜,功能被分得很細,因為這裡需要被擴充套件的地方很多,必須保證足夠的靈活性,以應對可能的變化。Bean的解析主要就是對Spring配置檔案的解析。這個解析過程主要透過BeanDefinitionReader來完成,看看Spring中BeanDefinitionReader的類結構圖,如下圖所示。
看看BeanDefinitionReader介面定義的功能來理解它具體的作用:
public interface BeanDefinitionReader {
//獲取BeanDefinitionRegistry註冊器物件
BeanDefinitionRegistry getRegistry();
@Nullable
ResourceLoader getResourceLoader();
@Nullable
ClassLoader getBeanClassLoader();
BeanNameGenerator getBeanNameGenerator();
/*
下面的loadBeanDefinitions都是載入bean定義,從指定的資源中
*/
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
4 BeanDefinitionRegistry解析
BeanDefinitionReader用來解析bean定義,並封裝BeanDefinition物件,而我們定義的配置檔案中定義了很多bean標籤,所以就有一個問題,解析的BeanDefinition物件儲存到哪兒?答案就是BeanDefinition的註冊中心,而該註冊中心頂層介面就是BeanDefinitionRegistry。
public interface BeanDefinitionRegistry extends AliasRegistry {
//往登錄檔中註冊bean
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
//從登錄檔中刪除指定名稱的bean
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
//獲取登錄檔中指定名稱的bean
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
//判斷登錄檔中是否已經註冊了指定名稱的bean
boolean containsBeanDefinition(String beanName);
//獲取登錄檔中所有的bean的名稱
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
繼承結構圖如下:
從上面類圖可以看到BeanDefinitionRegistry介面的子實現類主要有以下幾個:
-
DefaultListableBeanFactory
在該類中定義瞭如下程式碼,就是用來註冊bean
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
-
SimpleBeanDefinitionRegistry
在該類中定義瞭如下程式碼,就是用來註冊bean
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
5 建立容器
ClassPathXmlApplicationContext對Bean配置資源的載入是從refresh()方法開始的。refresh()方法是一個模板方法,規定了 IoC 容器的啟動流程,有些邏輯要交給其子類實現。它對 Bean 配置資源進行載入,ClassPathXmlApplicationContext透過呼叫其父類AbstractApplicationContext的refresh()方法啟動整個IoC容器對Bean定義的載入過程。