Spring源碼(IOC模塊)分析

    前言:Spring是我們日常Java web開發必不可少的框架,有着很優秀的設計思想,在熟練使用它的基礎上,很有必要了解其源碼,Spring主要有七大模塊,分別爲(IOC容器)Spring Core,應用上下文(Spring Context),Spring面向切面編程(Spring AOP),JDBC和DAO模塊(Spring DAO),對象實體映射(Spring ORM),Web模塊(Spring Web),MVC模塊(Spring Web MVC)。最核心的模塊爲IOC和AOP,也是面試常問及的內容,本文將從比較宏觀的角度分析IOC的源碼,不會太深入一些細節,希望能起到拋磚引玉的作用。

    IOC也就是控制反轉,讓對象的創建的權力反轉給IOC容器,具體通過Spring配置來創建對象,它的底層原理包括xml配置文件,dom4j解析,工廠設計模式,反射等等。使用Spring IOC容器,可以通過使用註解或xml配置的方式,Spring容器在啓動的時候,先會從xml配置或者註解中保存所有註冊進來的Bean定義信息。很經典的xml方式配置bean方式如下

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean id="boss" class="com.baobaotao.simple.Boss"></bean> 
</beans>

 

  由於現在普遍是Spring Boot項目,xml配置的方式也漸漸被註解方式取代了,註解方式更加方便,避免了xml文件一些繁瑣的配置,因此分析Spring源碼過程中也是以註解方式,但是原理是一樣的,配置xml只是多了一層解析xml文件罷了。

  OK,我們先看看bean的創建。這是主類

public class SpringIOCTest {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(IOCConfig.class);
		// 獲取Person bean
		Person bean = applicationContext.getBean(Person.class);
		System.out.println(bean.toString());
	}
}

配置類

@Configuration  //告訴Spring這是一個配置類
public class IOCConfig {
	//給容器中註冊一個Bean
	@Bean
	public Person person(){
		return new Person("lisi", 20);
	}
}

這就配置好一個Person類 bean,是不是很簡單!AnnotationConfigApplicationContext是註解的Spring上下文類,加載配置類,就可以完成配置,運行主類,就可以從Spring上下文中獲取到Person類對象!下面就分析下整個過程的原理。

進入AnnotationConfigApplicationContext構造方法,可以看到有三個方法,this()是調用無參構造函數,初始化讀取Bean定義信息的reader以及Bean定義包掃描對象,可以掃描一些@Componet,@Service等註解標註的組件,register方法就是註冊配置類,關鍵是下面refresh()函數

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				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...
				resetCommonCaches();
			}
		}
	}

下面逐一分析下refresh函數裏面做的事情

  1. prepareRefresh()函數是刷新前的預處理,裏面做的工作主要是初始化一些屬性設置;子類自定義個性化的屬性設置方法;檢驗屬性的合法等等
  2. obtainFreshBeanFactory()的作用是獲取BeanFactory,Spring創建Bean可以直接Bean相關參數創建,也可以通過BeanFactory的getObject方法獲取Bean
  3. prepareBeanFactory(beanFactory);這裏是BeanFactory的預準備工作(BeanFactory進行一些設置),如:

1)設置BeanFactory的類加載器、支持表達式解析器

2)添加部分BeanPostProcessor。BeanPostProcessor的作用是很強大的,它能在Bean初始化的前後做一些工作,例如ApplicationContextAwareProcessor的工作就是在其方法postProcessBeforeInitialization()中對繼承自ApplicationContextAware的bean進行處理,調用其setApplicationContext將Spring上下文注入。因此我們可以簡單寫一個實現ApplicationContextAware接口類重寫setApplicationContext方法就可以得到Spring上下文來做一些事情了。

  4.     postProcessBeanFactory(beanFactory)是BeanFactory準備工作完成之後進行的設置處理工作。子類可以通過重寫這個方法來在BeanFactory創建並預準備完成以後做進一步的設置操作,如下面的MyBeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
		int count = beanFactory.getBeanDefinitionCount();
		String[] names = beanFactory.getBeanDefinitionNames();
		System.out.println("當前BeanFactory中有"+count+" 個Bean");
		System.out.println(Arrays.asList(names));
	}

}
 5.     invokeBeanFactoryPostProcessor(beanFactory)爲執行BeanFactoryPostProcessor的方法。BeanFactoryPostProcessor爲BeanFactory的後置處理器,是在BeanFactory初始化之後執行的。
 6.     registerBeanPostProcessors(beanFactory)這步是註冊BeanPostProcessor,注意這是Bean的後置處理器,區別是BeanFactoryPostProcessor。兩者針對的對象不一樣,前者是針對Bean創建對象的方式,後者則是BeanFactory創建Bean的方式(Spring通過BeanFactory的getObject的方法獲取Bean對象).不同接口類型的BeanPostProcessor;在Bean創建前後的執行時機是不一樣的

        1)、獲取所有的 BeanPostProcessor;後置處理器都默認可以通過PriorityOrdered、Ordered接口來執行優先級
        2)、先註冊PriorityOrdered優先級接口的BeanPostProcessor;把每一個BeanPostProcessor;添加到BeanFactory中
   beanFactory.addBeanPostProcessor(postProcessor);
        3)、再註冊Ordered接口的
        4)、最後註冊沒有實現任何優先級接口的
        5)、最終註冊MergedBeanDefinitionPostProcessor;
        6)、註冊一個ApplicationListenerDetector;來在Bean創建完成後檢查是否是ApplicationListener,如果是
   applicationContext.addApplicationListener((ApplicationListener<?>) bean)

 7.          initMessageSource()主要是初始化MessageSource組件,來做國際化功能、消息綁定、消息解析

 8.          onRefresh()方法是空的,設計的目的主要是給子類重寫,在容器刷新的時候可以自定義邏輯

 9.          finishBeanFactoryInitialization(beanFactory):初始化所有剩下的單實例Bean 。

具體過程如下:
 1、beanFactory.preInstantiateSingletons();初始化後剩下的單實例bean
   1)、獲取容器中的所有Bean,依次進行初始化和創建對象
   2)、獲取Bean的定義信息;RootBeanDefinition
   3)、Bean不是抽象的,是單實例的,是懶加載;
      1)、判斷是否是FactoryBean;是否是實現FactoryBean接口的Bean;
      2)、不是工廠Bean。利用getBean(beanName);創建對象
         0、getBean(beanName); ioc.getBean();
         1、doGetBean(name, null, null, false);
         2、先獲取緩存中保存的單實例Bean。如果能獲取到說明這個Bean之前被創建過(所有創建過的單實例Bean都會被緩存起來)
            從private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);獲取的
         3、緩存中獲取不到,開始Bean的創建對象流程;
         4、標記當前bean已經被創建
         5、獲取Bean的定義信息;
         6、【獲取當前Bean依賴的其他Bean;如果有按照getBean()把依賴的Bean先創建出來;】
         7、啓動單實例Bean的創建流程;
            1)、createBean(beanName, mbd, args);
            2)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse);讓BeanPostProcessor先攔截返回代理對象;
               【InstantiationAwareBeanPostProcessor】:提前執行;
               先觸發:postProcessBeforeInstantiation();
               如果有返回值:觸發postProcessAfterInitialization();
            3)、如果前面的InstantiationAwareBeanPostProcessor沒有返回代理對象;調用4)
            4)、Object beanInstance = doCreateBean(beanName, mbdToUse, args);創建Bean
                1)、【創建Bean實例】;createBeanInstance(beanName, mbd, args);
                  利用工廠方法或者對象的構造器創建出Bean實例;
                2)、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                  調用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
                3)、【Bean屬性賦值】populateBean(beanName, mbd, instanceWrapper);
                  賦值之前:
                  1)、拿到InstantiationAwareBeanPostProcessor後置處理器;
                     postProcessAfterInstantiation();
                  2)、拿到InstantiationAwareBeanPostProcessor後置處理器;
                     postProcessPropertyValues();
                  =====賦值之前:===
                  3)、應用Bean屬性的值;爲屬性利用setter方法等進行賦值;
                     applyPropertyValues(beanName, mbd, bw, pvs);
                4)、【Bean初始化】initializeBean(beanName, exposedObject, mbd);
                  1)、【執行Aware接口方法】invokeAwareMethods(beanName, bean);執行xxxAware接口的方法
                     BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
                  2)、【執行後置處理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
                     BeanPostProcessor.postProcessBeforeInitialization();
                  3)、【執行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd);
                     1)、是否是InitializingBean接口的實現;執行接口規定的初始化;
                     2)、是否自定義初始化方法;
                  4)、【執行後置處理器初始化之後】applyBeanPostProcessorsAfterInitialization
                     BeanPostProcessor.postProcessAfterInitialization();
                5)、註冊Bean的銷燬方法;
            5)、將創建的Bean添加到緩存中singletonObjects;
         ioc容器就是這些Map;很多的Map裏面保存了單實例Bean,環境信息。。。。;
   所有Bean都利用getBean創建完成以後;
      檢查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就執行afterSingletonsInstantiated();

10.        finishRefresh()這一步就是完成BeanFactory的初始化創建工作,IOC容器到這裏就創建完成了。

      總結:

            1. Spring容器在啓動的時候,先會保存所有註冊進來的Bean定義信息,Bean定義信息有兩大來源,一個就是xml配置了,就是本文剛開始提到的Bean配置方式,另一種就是註解註冊Bean!就是平常我們開發常用到的@Service、@Componet、@Bean等等註解

            2.Spring容器會在合適的時機創建這些Bean,創建好就保存在容器中,如果是單例的Bean會緩存下來。最後到了統一創建剩下的Bean的時候,就是前面所提到的方法:finishBeanFactoryInitialization()

           3.後置處理器:BeanProcessor非常重要和強大,每一個Bean創建完成,都會使用各種後置處理器進行處理,從而達到增強Bean的功能,Spring另一個強大的模塊AOP面向切面編程也依靠到了BeanProcessor來實現

           4.上面其實還有某一兩個函數沒有提到,比如initApplicationEventMulticaster(),這個函數涉及到Spring事件驅動模型,來進行事件的監聽,派發。

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