1. 程式人生 > >Spring-BeanFactory原始碼分析(一)

Spring-BeanFactory原始碼分析(一)

前言

Spring 版本:5.0.9.RELEASE

正式進入Spring 原始碼分析這個模組了,對於spring這個龐大的工程,如果要一點點的完全分析是非常困難的,對於應用型框架,我還是偏向於掌握思想或者設計,而不是記住程式碼,對於初次看spring原始碼,相信大家都很頭大,而且看懂並不一定就是理解了,想要更好的效果,就要記錄下來,扯個題外話,LZ覺得寫部落格真的挺有癮的,一旦開始寫了,就很想繼續寫,每寫完一篇文章,感覺自己有產出,感覺很舒適,但是一旦歇菜,就又不想繼續寫了,這是一個不斷掙扎,不斷與自己鬥爭的過程,作為程式設計師 保持不斷的學習是非常重要的,不僅在技能上會得到加強,對自己人格發展也有很大影響,不論任何行業,持續學習都 是一個可怕的技能。

對於spring的分析,準確來說,不應該叫分析,而是學習,如果能將一個複雜的框架用簡單的方式,讓讀者明白,這個也是一種能力。

spring 的功能很強大,以至於不知道從何入手,因此,分析spring 那麼第一步就是拆解spring的功能,功能越單一越好,模組越清晰越好,這個也是軟體設計的原則。

網上很多都是從ClassPathXmlApplicationContext這個類開始分析的,LZ就不這樣了,LZ當初從這個類進入,然後就迷失自我了,先分析框框,細節不懂沒關係,畢竟程式碼不是你寫的,你看你同事寫的程式碼,你可能也會嗤之以鼻。

BeanFactory

BeanFactory提供的是最基本的IOC容器的功能,BeanFactory 只是一個介面類,並沒有給出容器的具體實現,當然,它有不同的實現類,來定義或者擴充某個功能。這篇文章的主角就是它啦。

啟動IOC容器

下面是一段簡單的程式碼,通過程式設計啟動IOC 容器:

public void TestDefaultListableBeanFactory(){

  ClassPathResource resource  = new ClassPathResource("spring.xml");

  DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

  XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

  reader.loadBeanDefinitions(resource);

  MyBean bean = factory.getBean(MyBean.class);

  System.out.println(bean.toString());

}

spring.xml 配置檔案裡面很簡單:

<bean id="myBean" class="com.study.spring.bean.MyBean" />

這樣,我們就可以通過factory物件來使用DefaultListableBeanFactory 這個IOC容器了,在使用IOC容器時,需要如下步驟: 1) 建立IOC配置檔案的抽象資源,即配置檔案

2)建立一個BeanFactory,這裡使用DefaultListableBeanFactory

3)建立一個載入BeanDefinition的讀取器,這裡使用XmlBeanDefinitionReader 來載入XML檔案形式的BeanDefinition。

4)從定義好的資源位置讀取配置資訊,具體的解析過程由XmlBeanDefinitionReader 來完成。

通過一個簡短的程式碼就可以啟動spring,核心就在於DefaultListableBeanFactory,暫時就不直接跟蹤流程了,還是來看看整個BeanFactory的設計。

BeanFactory 體系

BeanFactory,從名字上也很好理解,生產管理 bean 的工廠(容器),它負責生產和管理各個 bean 例項。

我們來看下和 BeanFactory 介面相關的主要的繼承結構:

diagram

上面的繼承關係去除了目前不需要的類。

emmmmm,這圖看著有點頭大,慢慢來,先主要關注左邊部分,梳理一下各個BeanFactory的職能,怎麼梳理?,看原始碼咯。

BeanFactory

BeanFactory 是頂級介面,定義了IOC容器最基本的形式。

public interface BeanFactory {

    //這裡可以暫時不用管
	String FACTORY_BEAN_PREFIX = "&";

	Object getBean(String name) throws BeansException;
	... //省略其它方法
}

定義了一些基本介面,例如 獲取bean,當然還有一些其它介面,這裡就不列出了,需要自己去了解一下。

至於 FACTORY_BEAN_PREFIX 這個其實在這裡可以忽略,這裡LZ還是簡單提一下,如果不明白也無妨,與BeanFactory很相似的有一個叫FactoryBean的類,從名字上很容易混淆,BeanFactory 首先是Factoyr,而FactoryBean 是bean,只是 是一種特殊的bean, 這種特殊的bean會生產另一種bean, 對於普通的bean,通過BeanFactory 的 getBean方法可以獲取這個bean,而對於FactoryBean 來說,通過getBean 獲得的是 FactoryBean 生產的bean,而不是FactoryBean 本身,如果想要獲取FactoryBean 本身,那麼可以加字首&,那麼spring 就明白,原來你是需要FactoryBean 。這個可能會在後面AOP的部分,展開來講,這裡就先說這麼多了。

ListableBeanFactory

public interface ListableBeanFactory extends BeanFactory {

    // 對於給定的名字是否含有BeanDefinition
	boolean containsBeanDefinition(String beanName);

    // 返回工廠的BeanDefinition總數
	int getBeanDefinitionCount();
	
    // 返回工廠中所有Bean的名字
	String[] getBeanDefinitionNames();

    // 返回對於指定型別 獲取bean的名字
	String[] getBeanNamesForType(ResolvableType type);
    
    //獲取包含某個註解 bean的名字
	String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);

    // 根據指定Bean名和註解型別查詢指定的Bean
	<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
			throws NoSuchBeanDefinitionException;

}

通過名字可以猜到,這定義的一個可列舉(迭代)的BeanFactory,通過這個BeanFactory 可以查詢特定的Bean,相比頂級的BeanFactory,其查詢更加多樣化,牽涉到了BeanDefinition,BeanName,註解。

等等,BeanDefinition 是什麼,其實這個通過名字就知道了,這個包裝的是Bean的定義,它現在還不是我們需要探討的內容,從名字能理解有個印象就ok。

HierarchicalBeanFactory

public interface HierarchicalBeanFactory extends BeanFactory {

	BeanFactory getParentBeanFactory();

	/**
	 * Return whether the local bean factory contains a bean of the given name,
	 * ignoring beans defined in ancestor contexts.
	 * <p>This is an alternative to {@code containsBean}, ignoring a bean
	 * of the given name from an ancestor bean factory.
	 */
	boolean containsLocalBean(String name);

}

分層式的BeanFactory,這個工廠介面非常簡單,實現了Bean工廠的分層。相對於BeanFactory介面,它只擴充套件了一個重要的功能——工廠分層,可以指定父工廠(容器),同時查詢bean的時候,可以只查詢本容器,忽略父容器。

AutowireCapableBeanFactory

public interface AutowireCapableBeanFactory extends BeanFactory {

	//  這個常量表明工廠沒有自動裝配的Bean
	int AUTOWIRE_NO = 0;

	//表明根據名稱自動裝配
	int AUTOWIRE_BY_NAME = 1;

	//表明根據型別自動裝配
	int AUTOWIRE_BY_TYPE = 2;

	//表明根據構造方法裝配
	int AUTOWIRE_CONSTRUCTOR = 3;

	//被廢棄了
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;

	<T> T createBean(Class<T> beanClass) throws BeansException;

	//  給定物件,根據註釋、後處理器等,進行自動裝配
	void autowireBean(Object existingBean) throws BeansException;

	...//省略後續方法
}

AutowireCapableBeanFactory 目前還沒有深入的研究,這個BeanFactory 增加了註解功能,可以通過註解進行裝配(操作)的工廠(容器)。

小結

上面三個 Factory 是 BeanFactory 介面的直系親屬,三種不同樣式的BeanFactory ,分層容器,可列舉(查詢)容器,自動裝配容器,職能單一原則,這種介面設計,應該平常工作中經常遇到吧。

接下來在看看其它更多樣化的 BeanFactory 。

ConfigurableBeanFactory

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {

	String SCOPE_SINGLETON = "singleton";

	String SCOPE_PROTOTYPE = "prototype";
    
    //設定父容器
	void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;

	void setBeanClassLoader(ClassLoader beanClassLoader);

	ClassLoader getBeanClassLoader();

	void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);

	BeanExpressionResolver getBeanExpressionResolver();

    /*
     * 設定 轉換服務
     */
	void setConversionService(ConversionService conversionService);

	ConversionService getConversionService();

	void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);

    /*
     * 註冊屬性編輯器
     */
	void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);

	void copyRegisteredEditorsTo(PropertyEditorRegistry registry);

	void setTypeConverter(TypeConverter typeConverter);

	TypeConverter getTypeConverter();

    //設定一個Bean後處理器
	void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

	int getBeanPostProcessorCount();

	void registerScope(String scopeName, Scope scope);

	String[] getRegisteredScopeNames();

	Scope getRegisteredScope(String scopeName);

	void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);
    /*
     * 給指定的Bean註冊別名
     */
	void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;

	BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //判斷指定Bean是否為一個工廠Bean
	boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;

	void setCurrentlyInCreation(String beanName, boolean inCreation);

	boolean isCurrentlyInCreation(String beanName);

	void registerDependentBean(String beanName, String dependentBeanName);

	String[] getDependentBeans(String beanName);

	String[] getDependenciesForBean(String beanName);

	void destroyBean(String beanName, Object beanInstance);

	void destroyScopedBean(String beanName);

	void destroySingletons();
	
	...//省略部分方法

}

ConfigurableBeanFactory 繼承了 HierarchicalBeanFactory,SingletonBeanRegistry

先看一下介面SingletonBeanRegistry的原始碼:

SingletonBeanRegistry

public interface SingletonBeanRegistry {

    //註冊一個單例類  
	void registerSingleton(String beanName, Object singletonObject);


	Object getSingleton(String beanName);


	boolean containsSingleton(String beanName);


	String[] getSingletonNames();

	int getSingletonCount();

    //不清楚
	Object getSingletonMutex();

}

可以看到,SingletonBeanRegistry這個介面非常簡單,實現了單例類註冊的功能。

ConfigurableBeanFactory同時繼承了HierarchicalBeanFactory 和 SingletonBeanRegistry 這兩個介面,即同時繼承了分層和單例類註冊的功能。

ConfigurableBeanFactory 正如其名字一樣,可以配置的BeanFactory,裡面有很多介面方法,我也沒有去細研究每一個方法,後面用到了,再來具體分析就可以了,瞭解瞭解,知道大概用處就可以了。

ConfigurableListableBeanFactory

public interface ConfigurableListableBeanFactory
		extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {

    //忽略自動裝配的依賴型別
	void ignoreDependencyType(Class<?> type);
    
    //忽略自動裝配的介面
	void ignoreDependencyInterface(Class<?> ifc);

    //返回註冊的Bean定義
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;


	Iterator<String> getBeanNamesIterator();

	...//忽略部分方法
}

工廠介面ConfigurableListableBeanFactory同時繼承了3個介面,ListableBeanFactory、AutowireCapableBeanFactory 和 ConfigurableBeanFactory,可以說功能以及很全面了。

對於BeanFactory 體系中左邊部分,大致差不多了,現在看看右半邊情況

BeanDefinitionRegistry

顧名思義,這個是註冊 BeanDefinition的

public interface BeanDefinitionRegistry extends AliasRegistry {

    //給定bean名稱,註冊一個新的bean定義
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

    //根據指定Bean名移除對應的Bean定義
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    根據指定bean名得到對應的Bean定義
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    查詢,指定的Bean名是否包含Bean定義
	boolean containsBeanDefinition(String beanName);

    //返回本容器內所有註冊的Bean定義名稱
	String[] getBeanDefinitionNames();

    //指定Bean名是否被註冊過。
	int getBeanDefinitionCount();

   //指定Bean名是否被註冊過。
	boolean isBeanNameInUse(String beanName);

}

這個介面很簡單,就是對BeanDefinition的操作,然而我們還沒有了解BeanDefinition 的結構,但是並不影響我們分析,因為從名字就知道這個指代的是一個bean的定義,也就是將xml中的bean 翻譯成了具體的資料結構。

現在回過頭來,我們再看看DefaultListableBeanFactory類圖

diagram

對於左邊部分,則是各種功能的BeanFactory,右邊部分則是對BeanDefinition的功能操作,中間部分則是單例Bean功能服務,中間部分我們沒有分析原始碼,但是通過名字我們已經很好的知道了它的功能,而FactoryBeanRegistrySupport 則表示了對 FactoryBean的支援,(FactoryBean在前面BeanFactory簡單提了一下喲)

現在對每個BeanFactory的職能心裡大概有譜了,這樣在後面的時候,才知道這個功能屬於哪個模組,而不至於腦袋一團漿糊。

對於DefaultListableBeanFactory 我們並沒有取分析它,因為DefaultListableBeanFactory 中實現了上面介面中的所有方法,涉及了很多細節,從程式碼角度來看的話,那真的是很難一下分析透,但是如果從功能模組上來看的話,我們也知道了它大概可以幹什麼,可以說是一個比較成熟的容器了,既然現在我們知道了裝bean的容器了,那麼bean又從何處來呢,當然是xml,但是xml又如何轉換成資料結構的呢,這個就需要回到我們最開的程式碼了:

public void TestDefaultListableBeanFactory(){

  ClassPathResource resource  = new ClassPathResource("spring.xml"); //3

  DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); //5

  XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//7

  reader.loadBeanDefinitions(resour	ce);//9

  MyBean bean = factory.getBean(MyBean.class); //11

  System.out.println(bean.toString());

}

現在第5,11行程式碼我們已經大致清楚了,主要的還剩3,4,9行程式碼了,這個就先留到後面再來吧。

BeanDefinition

Bean的定義主要由BeanDefinition來描述的,作為Spring中用於包裝Bean的資料結構,先來看看BeanDefinition一個繼承結構吧(非完整繼承結構)

20180913111748

一個BeanDefinition描述了一個bean的例項,包括屬性值,構造方法引數值和繼承自它的類的更多資訊。

BeanDefinition 原始碼淺析

//標準單例作用域 識別符號:“singleton”。
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

//標準原型作用域的範圍識別符號:“prototype”。
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

//表示BeanDefinition是應用程式主要部分的角色提示。 通常對應於使用者定義的bean。
int ROLE_APPLICATION = 0;

//表示BeanDefinition是某些大型配置的支援部分的角色提示,通常是一個外部ComponentDefinition。
//當檢視某個特定的ComponentDefinition時,認為bean非常重要,
//以便在檢視應用程式的整體配置時能夠意識到這一點。

int ROLE_SUPPORT = 1;

//角色提示表明一個BeanDefinition是提供一個完全背景的角色,並且與終端使用者沒有關係。
int ROLE_INFRASTRUCTURE = 2;

ROLE_SUPPORT =1實際上就是說,我這個Bean是使用者的,是從配置檔案中過來的。

ROLE_INFRASTRUCTURE = 2 就是說 這Bean是Spring自己的,

上面是BeanDifinition的一些基本屬性資訊,一個就是標識下當前Bean的作用域,另外就是標識一下這個Bean是內部的還是外部的。下面來看這個介面為其子類都提供了哪些具體的行為方法:

1.當前Bean的className get&set方法

//指定此bean定義的bean類名稱。
//類名稱可以在bean factory後期處理中修改,通常用它的解析變體替換原來的類名稱。
void setBeanClassName(String beanClassName);

//返回此bean定義的當前bean類名稱。
//需要注意的是,這不一定是在執行時使用的實際類名,以防子類定義覆蓋/繼承其父類的類名。
//此外,這可能只是呼叫工廠方法的類,或者它 在呼叫方法的工廠bean引用的情況下甚至可能是空的。
//因此,不要認為這是在執行時定義的bean型別,而只是將其用於在單獨的bean定義級別進行解析。
String getBeanClassName();

2.Bean的作用域get&set方法

//覆蓋此bean的目標範圍,指定一個新的範圍名稱。
void setScope(String scope);
//返回此bean的當前目標作用域的名稱,如果沒有確定,返回null
String getScope();

3.懶載入的get&set方法

//設定這個bean是否應該被延遲初始化。如果{false},那麼這個bean將在啟動時由bean工廠例項化,
//這些工廠執行單例的立即初始化。
//懶載入 <bean lazy-init="true/false">
void setLazyInit(boolean lazyInit);
//返回這個bean是否應該被延遲初始化,即不是在啟動時立即例項化。只適用於單例bean。
boolean isLazyInit();

4.依賴關係設定

//設定這個bean依賴被初始化的bean的名字。 bean工廠將保證這些bean首先被初始化。
//<bean depends-on="">
void setDependsOn(String... dependsOn);
//返回這個bean依賴的bean名稱。
String[] getDependsOn();

5.是否是自動轉配設定

//設定這個bean是否是獲得自動裝配到其他bean的候選人。
//需要注意是,此標誌旨在僅影響基於型別的自動裝配。
//它不會影響按名稱的顯式引用,即使指定的bean沒有標記為autowire候選,也可以解決這個問題。
//因此,如果名稱匹配,通過名稱的自動裝配將注入一個bean。
void setAutowireCandidate(boolean autowireCandidate);

//返回這個bean是否是自動裝配到其他bean的候選者。就是是否在其他類中使用autowired來注入當前Bean的
//是否為被自動裝配 <bean autowire-candidate="true/false">
boolean isAutowireCandidate();

並沒有完全列舉 BeanDifinition 中的方法或者屬性,大致明白 Bean的定義主要由BeanDefinition來描述的,作為Spring中用於包裝Bean的資料結構就可以了,關於BeanDifinition 的更多介面實現,這個根據自己情況去看看就可以了。

小結

瞭解了BeanFactory的大致結構後,來看看下面一段簡單程式碼,相信理解就更加深刻了:

public void TestDefaultListableBeanFactory(){

  DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

  AbstractBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);

  factory.registerBeanDefinition("myBean",beanDefinition);

  //可以通過構造方法注入依賴,當然我們這裡沒有
  //beanDefinition.setConstructorArgumentValues();

  //可以通過 setter 方法注入依賴,當然我們這裡也沒有
  //beanDefinition.setPropertyValues();

  MyBean bean = factory.getBean(MyBean.class);

  System.out.println(bean.toString());

}

在前面我們用的ClassPathResource,XmlBeanDefinitionReader 從檔案中讀取的bean配置資訊,現在我們知道了BeanDifinition 以及BeanDefinitionRegistry,那麼其實我們可以手動註冊BeanDifinition ,這樣我在最開始的程式碼基礎上,又再次細分了功能了,層次也更加的清楚了。

總結

我們從 DefaultListableBeanFactory 出發,大致瞭解了一下 BeanFactory的體系結構,BeanFactory有三個直系親屬:

ListableBeanFactory(可列舉的容器(多花樣查詢)),HierarchicalBeanFactory(分層次容器,可有父容器),AutowireCapableBeanFactory(自動裝配容器),這三個容器定義了BeanFactory的基本面貌,在這個三個直系親屬下面又派生了兩個複雜的容器:ConfigurableBeanFactory,ConfigurableListableBeanFactory,可配置的(可操作)的容器,通過這兩個BeanFactory 可有修改容器中的bean,功能又更加高階了,集成了單例bean 服務,以及BeanDefinition 註冊服務,那麼對於 DefaultListableBeanFactory 來說,此時它就是一個可註冊,可配置,可獲取的BeanFactory ,就容器方面而言功能已經健全了。

參考

spring 技術內幕