1. 程式人生 > >SpringFramework之IoC容器初始化

SpringFramework之IoC容器初始化

**原創文章,轉發請標註https://www.cnblogs.com/boycelee/p/12595884.html** [toc] ## 分析例子 #### 啟動類 Application,使用的是ClassPathXmlApplicationContext來載入xml檔案 ```java /** * @author jianw.li * @date 2020/3/16 11:53 PM * @Description: TODO */ public class MyApplication { private static final String CONFIG_LOCATION = "classpath:application_context.xml"; private static final String BEAN_NAME = "hello"; public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext(CONFIG_LOCATION); Hello hello = (Hello) ac.getBean(BEAN_NAME); hello.sayHello(); } } ``` #### Bean ```java /** * @author jianw.li * @date 2020/3/16 11:53 PM * @Description: TODO */ public class Hello { public void sayHello() { System.out.println("Hello World"); } } ``` #### 配置檔案 ​ 在resources下建立名為classpath:application_context.xml的配置檔案,並配置好Bean ```xml ``` ## 總體結構 ​ **ClassPathXmlApplicationContext繼承體系如下:** ![KWJf7l](https://gitee.com/leeboyce/imagebed/raw/20200305-image/uPic/KWJf7l.png) ​ **IoC總體結構圖如下:** ![image-20200322155805716](https://gitee.com/leeboyce/imagebed/raw/20200305-image/uPic/image-20200322155805716.png) ## 原始碼分析 #### ClassPathXmlApplicationContext ```java //建構函式,建立ClassPathXmlApplicationContext,其中configLocation為Bean所在的檔案路徑 public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { //null super(parent); //設定配置路徑至ApplicationContext中 setConfigLocations(configLocations); if (refresh) { //核心方法,refresh會將舊的ApplicaionContext銷燬 refresh(); } } ``` #### AbstractApplicationContext ##### refresh ​ 核心方法,refresh銷燬舊ApplicationContext,生成新的ApplicationContext ```java @Override public void refresh() throws BeansException, IllegalStateException { //加鎖.沒有明確物件,只是想讓一段程式碼同步,可以建立Object startupShutdownMonitor = new Object() synchronized (this.startupShutdownMonitor) { // 為context重新整理準備.設定啟動時間,設定啟用狀態等 prepareRefresh(); // 告知子類重新整理內部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(); } } } ``` ##### obtainFreshBeanFactory ​ 告知子類重新整理內部bean factory. ​ 核心方法,初始化BeanFactory、載入Bean、註冊Bean ```java protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //重新整理Bean工廠,關閉並銷燬舊BeanFacroty refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } ``` ##### refreshBeanFactory ​ 關閉並銷燬舊BeanFactory,建立與初始化新BeanFactory。**為什麼是DefaultListableBeanFactory?** ```java @Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //初始化DefaultListableBeanFactory,為什麼選擇例項化DefaultListableBeanFactory?而不是其他的Bean工廠 DefaultListableBeanFactory beanFactory = createBeanFactory(); //Bean工廠序列化設定id beanFactory.setSerializationId(getId()); //定製Bean工廠,設定不允許覆蓋Bean,不允許迴圈依賴等 customizeBeanFactory(beanFactory); //將Bean載入至Bean工廠中 loadBeanDefinitions(beanFactory); //此處synchronized塊與#hasBeanFactory中的synchronized塊存在關聯,此處鎖住之後hasBeanFactory中的synchronized塊將等待 //避免beanFactory未銷燬或未關閉的情況 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } ``` ##### customizeBeanFactory ​ 定製BeanFactory。設定Bean覆蓋、迴圈依賴等。**什麼是迴圈依賴?** ``` protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { //預設值為false不允許對Bean進行覆蓋 beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { //預設值為false,不允許迴圈依賴 beanFactory.setAllowCircularReferences(this.allowCircularReferences); } } ``` #### AbstractXmlApplicationContext ##### loadBeanDefinitions ```java @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } ``` ##### loadBeanDefinitions ```java protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { //載入資源物件,最終還是會回到這種方式去載入bean. reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { //載入資源路徑嗎 reader.loadBeanDefinitions(configLocations); } } ``` #### AbstractBeanDefinitionReader ##### loadBeanDefinitions ```java @Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; //迴圈配置檔案路徑 for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; } ``` ```java public int loadBeanDefinitions(String location, @Null