IOC(二)DefaultListableBeanFactory

前言

上一章咱們已經初步認識了BeanFactory和BeanDefinition,一個是IOC的核心工廠接口,一個是IOC的bean定義接口。

spring沒法讓BeanFactory持有一個Map<String,Object>來完成bean工廠的功能,是由於spring的初始化是能夠控制的,能夠到用的時候纔將bean實例化供開發者使用,除非咱們將bean的lazy-init屬性設置爲true,初始化bean工廠時採用延遲加載。

那麼知道了上述兩個接口,我相信很多人甚至不看源碼都已經猜到spring是如何作的了。沒錯,就是讓bean工廠持有一個Map<String,BeanDefinition>,這樣就能夠在任什麼時候候咱們想用哪一個bean,取到它的bean定義,咱們就能夠創造出一個新的實例。java

接口固然不可能持有這樣一個對象,那麼這個對象必定是在BeanFactory的某個實現類或者抽象實現類當中所持有的,來看DefaultListableBeanFactory。spring

1、源碼分析

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

	private static Class<?> javaUtilOptionalClass = null;

	private static Class<?> javaxInjectProviderClass = null;

	static {
		try {
			javaUtilOptionalClass =
					ClassUtils.forName("java.util.Optional", DefaultListableBeanFactory.class.getClassLoader());
		}
		catch (ClassNotFoundException ex) {
			// Java 8 not available - Optional references simply not supported then.
		}
		try {
			javaxInjectProviderClass =
					ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - Provider interface simply not supported then.
		}
	}


	/** Map from serialized id to factory instance */
	private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
			new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);

	/** Optional id for this factory, for serialization purposes */
	private String serializationId;

	/** Whether to allow re-registration of a different definition with the same name */
	private boolean allowBeanDefinitionOverriding = true;

	/** Whether to allow eager class loading even for lazy-init beans */
	private boolean allowEagerClassLoading = true;

	/** Optional OrderComparator for dependency Lists and arrays */
	private Comparator<Object> dependencyComparator;

	/** Resolver to use for checking if a bean definition is an autowire candidate */
	private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();

	/** Map from dependency type to corresponding autowired value */
	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);

	/** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

	/** Map of singleton and non-singleton bean names, keyed by dependency type */
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

	/** Map of singleton-only bean names, keyed by dependency type */
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

	/** List of bean definition names, in registration order */
	private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);

	/** List of names of manually registered singletons, in registration order */
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);

	/** Cached array of bean definition names in case of frozen configuration */
	private volatile String[] frozenBeanDefinitionNames;

	/** Whether bean definition metadata may be cached for all beans */
	private volatile boolean configurationFrozen = false;複製代碼
該類的屬性就在這裏了,至於方法此處被我省略,由於太長了...

看它名字就知道,這是一個默認的bean工廠實現類,根據類註釋能夠知道這是一個完整的,成熟的IOC容器。也就是說,若是你須要的功能很是單一,這個實現類已經足夠能夠知足你了,而之後若是你想要對spring的容器擴展,那麼只須要擴展或者持有這個對象便可。

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);複製代碼
看到這一行,其實已經證實了個人猜想,它所註釋的意思是bean定義的map對象,採用beanName做爲key值。

只繼承了一個抽象類,同時把集大成的接口ConfigurableListableBeanFactory給實現了,同時還有BeanDefinitionRegistry接口,從名字上看就知道是BeanDefinition的註冊接口。

看到這裏,思路已經很明確了,bean工廠的初始化其實就是往這個Map裏填充東西。只要把咱們XML文件中定義的bean都填充到這裏,其實這個工廠就已經能夠工做了。

那麼從如今來看,咱們須要什麼才能把Map填充呢?也就是初始化bean工廠呢,或者說創建IOC容器。

2、IOC容器實現原理討論

此次先不關注源碼,先首先看看它的用法。

ClassPathResource res=new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
Performer performer=(Performer) factory.getBean("dancer");
performer.perform();複製代碼
簡單解釋一下:
1.咱們在beans.xml中定義了一個Bean,id爲「dancer」,實現了Performer接口。參考自<Spring in action>例子.
2.利用Resource抽象實現類,來包裝這個包含了BeanDefinition的定義信息。
3.建立一個BeanFactory,DefaultListableBeanFactory
4.建立一個載入BeanDefinition的讀取器,經過回調配置給BeanFactory.
5. 從定義好的Resource中,讀取配置信息。由XmlBeanDefinitionReader完成解析,完成整個載入和註冊Bean定義的過程。
6. 經過BeanFactory的getBean()方法,獲取對應的Bean。這裏涉及到了Bean的實例化以及依賴注入

依賴注入的過程

以上過程能夠當作是IOC容器初始化的過程,這個初始化過程完成的主要工做是完成BeanDefinition在IOC容器中的數據映射。而這裏並無實例化任何對象,也歷來沒有完成過依賴注入的過程。

依賴注入是經過getBean方法完成的,固然若是將lazy-init屬性設置爲true,則能夠在初始化的過程當中完成依賴注入,實現預實例化。緩存

Performer performer=(Performer) factory.getBean("dancer");經過getBean得到名爲「dancer」的對象,而factory如今保有的僅僅是鍵爲「dancer」的BeanDefinition對象(保存在Map中)。ide

而經過源碼能夠發現getbean()方法是由AbstractBeanFactory實現的,而具體實現又跳到了doGetBean()方法,源碼分析

doGetBean()方法負責從Bean工廠中獲取bean對象的具體實現,下面來看看該方法的具體實現:this

  1. 檢查手動註冊的單例集合緩存中是否含有該bean對象,如有,則取出返回,不然繼續執行;
  2. 檢查該bean是否已經建立,從而判斷是否屬於循環引用,如果,拋出異常返回,不然繼續執行;
  3. 判斷bean工廠中是否存在該bean definition,若存在,則取出返回,不然繼續執行;
  4. 初始化該bean所依賴的bean對象;
  5. 判斷該bean是不是單例模式(singleton),如果,建立單例對象,不然繼續執行;
  6. 判斷該bean是不是原型模式(prototype),如果,建立原型對象,不然繼續執行;
  7. 建立自定義類型(scope)bean對象。
  8. 從上面對doGetBean方法分析,可看出建立並獲取bean對象是一個很是複雜的過程,並非簡簡單單的放入Map中再從其中取出。

3、小結

      整篇文章下來,能夠看到DefaultListableBeanFactory實現了IOC容器的初始化而且經過getbean()完成了依賴注入。整個IOC容器初始化過程總結起來就是定位(定位到配置文件)、解析(解析配置文件,通常是XML)、註冊(將讀出來的數據放到map中)。
      這篇文章裏我並無仔細記錄源碼的執行過程,由於內容實在是太多,我只是經過一個demo講述了DefaultListableBeanFactory獲取一個bean的大概過程。具體源碼執行過程還須要各位讀者本身去探索,我也是本身經過源碼把這個過程探索了一遍才知道IOC容器初始化的過程,不過其中有些地方尚未徹底領悟,待本身有所提高後再回來看看應該會有不同的感覺。


依賴注入過程參考自
相關文章
相關標籤/搜索