Spring源碼解析一:Spring IOC容器的設計

1,IOC接口的設計

在這裏插入圖片描述
這裏的接口設計有兩條主線:BeanFactory和ApplicationContext

1、BeanFactory–>HierarchicalBeanFactory–>ConfigurableBeanFactory:這是BeanFactory的設計路線,BeanFactory定義了基本的IOC容器規範,HierarchicalBeanFactory中增加了getParentBeanFactory方法,具備了雙親IOC容器的管理功能;ConfigurableBeanFactory中新增一些配置功能。

2、ApplicationContext應用上下文接口:繼承了HierarchicalBeanFactory、ListableBeanFactory等BeanFactory的子接口,這條分支使得ApplicationContext具備了IOC容器的基本功能;在繼承MessageSource、ApplicationEventPublisher等接口的時候,使得ApplicationContext這個簡單的IOC容器添加了許多高級容器的特性。ApplicationContext的子接口有ConfigurableApplicationContext以及在WEB環境下使用的WebApplicationContext。

2,BeanFactory接口的設計

public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";

	Object getBean(String name) throws BeansException;

	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	boolean containsBean(String name);

	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	String[] getAliases(String name);

}

  1. 用戶使用容器的時候,可使用“&”來得到FactoryBean本身,用來區分FactoryBean產生的對象和FactoryBean本身。舉例來說userObject是一個FactoryBean,那麼&userObject得到的是FactoryBean ,而不是得到userObject這個FactoryBean所產生的對象
  2. BeanFactory接口設計了getBean()這個方法,這個方法是IOC容器api的方法,通過這個方法可以取得IOC容器中管理的Bean,bean的取得是通過指向名字來索引的。
  3. 通過接口方法containsBean讓用戶能夠判斷容器中是否含有指定名字的bean。
  4. 通過接口方法isSingleton可以讓用戶查詢指定名字的bean是否是singleton屬性 的bean,對於singleton屬性,用戶可在BeanDefinition中去指定。
  5. 通過接口方法isPrototype可以讓用戶查詢指定名字的bean是否是prototype屬性 的bean,對於prototype屬性,用戶可在BeanDefinition中去指定。
  6. 通過接口方法isTypeMatch,查詢指定名字的bean的Class類型是否是特定的Class類型
  7. 通過接口方法getType查詢指定名字bean的Class類型
  8. 通過接口方法getAliases查詢指定名字bean所以的別名,別名是在BeanDefinition中定義的

3,XmlBeanFactory的解讀

在這裏插入圖片描述
XmlBeanFactory是IOC容器系列最底層的實現,它繼承自DefaultListableBeanFactory這個類。而後者是Spring中非常重要的一個類,它是Spring容器中一個基本產品,可以把它當做一個默認的功能完整的IOC容器來使用。

XmlBeanFactory除了從DefaultListableBeanFactory繼承到IOC容器基本功能之外,還新增了一些其他功能,從名稱就可以猜測出來,它是一個可以讀取以XML文件方式定義BeanDefinition的容器。

XmlBeanFactory源碼如下:

public class XmlBeanFactory extends DefaultListableBeanFactory
{
  private final XmlBeanDefinitionReader reader;

  public XmlBeanFactory(Resource resource)
    throws BeansException
  {
    this(resource, null);
  }

  public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)
    throws BeansException
  {
    super(parentBeanFactory);

    this.reader = new XmlBeanDefinitionReader(this);

    this.reader.loadBeanDefinitions(resource);
  }
}

實際上,實現XML讀取功能並不是直接由XmlBeanFactory來完成的。而是由XmlBeanFactory內部定義的XmlBeanDefinitionReader來進行處理的。在構造XmlBeanFactory容器的時候,需要給出BeanDefinition的信息來源,而這個信息來源需要封裝成Spring中的Resource類的形式給出。

來看下一個基本的IOC容器的初始化過程:

1、創建IOC配置文件的抽象資源,也就是源碼中的Resource,這個Resource中包含了BeanDefinition的定義信息。

2、通過構造函數創建一個BeanFactory。

3、創建一個載入BeanDefinition的讀取器,即源碼中的reader。這裏使用XmlBeanDefinitionReader來載入XML文件形式的BeanDefinition。

4、調用reader的loadBeanDefinitions方法,來完成從Resource中載入BeanDefinition信息,從而完成IOC容器的初始化。

我們可以將上面的源碼做簡化,使用編程式的方式來表達IOC容器的初始化:

ClassPathResource resource = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);

DefaultListableBeanFactory是IOC容器的一個基類,XmlBeanFactory是在其基礎上擴展而來的。而其他的IOC容器,例如ApplicationContext,它的實現原理和XmlBeanFactory類似,也是通過擴展DefaultListableBeanFactory來獲取基本的IOC容器功能的。

4,ApplicationContext的設計原理

在這裏插入圖片描述
1、ApplicationContext繼承接口ListableBeanFactory、HierarchicalBeanFactory,實現了IOC容器的基本功能。

2、繼承接口MessageSource:支持不同信息源,支持國際化的實現。

3、繼承接口ResourceLoader:支持該容器可以從不同I/O途徑得到Bean的定義信息。

4、繼承接口ApplicationEventPublisher:在上下文中引入了事件機制。這些事件機制和Bean的生命週期結合爲Bean的管理提供了便利。

ApplicationContext增加了這些附加功能,使得基本IOC容器的功能更加豐富,所以建議在開發應用的時候使用ApplicationContext作爲IOC容器的基本形式。

以子類FileSystemXmlApplicationContext的實現爲例說明其設計原理。接口設計圖如下:
在這裏插入圖片描述
這個接口設計中,ApplicationContext應用上下文的主要功能已經在FileSystemXmlApplicationContext的基類AbstractXmlApplicationContext中實現了,而FileSystemXmlApplicationContext作爲一個具體的IOC容器,只需要實現和其本身相關的功能即可,源碼如下:

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    throws BeansException
  {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh)
      refresh();
  }

  protected Resource getResourceByPath(String path)
  {
    if ((path != null) && (path.startsWith("/"))) {
      path = path.substring(1);
    }
    return new FileSystemResource(path);
  }
}

這裏面有兩個主要的方法:refresh()、getResourceByPath(String path)

1、refresh涉及到IOC容器啓動的一系列操作,由於這個啓動過程對於不同類型的容器來說都是相似的,所以這個啓動過程被封裝在基類中,具體的容器只需要調用即可。refresh方法後面會有詳細介紹。

2、getResourceByPath這個方法是跟FileSystemXmlApplicationContext區別於其他具體容器的功能。通過這個方法可以讓容器在文件系統中讀取以XML形式存在的BeanDefinition。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章