Spring IOC源碼跟蹤記錄-基於XML

what is IOC?

IOC(Inversion of Control )控制反轉,是Spring框架最重要的一個特性,提供了一個裝載類的容器來爲類之間進行解耦,並提供了一系列的擴展接口,使得開發者能夠在bean的生命週期裏自定義一些行爲操做。java

在沒有IOC以前,類與類之間的耦合關係是這樣的。這兒僅僅只有5個類,類之間的耦合關係就如此複雜,不可思議當類的數量隨着業務發展而爆炸增多的時候,耦合關係是多麼的糟糕。spring

clipboard.png

在有了IOC以後,類與類之間的耦合關係是這樣的。全部類都註冊在IOC容器上,全部類只和IOC容器耦合,而且IOC容器爲全部管理的類提供生命週期的管理。緩存

clipboard.png

how IOC do?

能夠看出來IOC容器很像咱們生活中的百貨商場,咱們須要什麼東西均可以去百貨商場買到,在沒有百貨商場之前咱們買菜須要去菜市場,買手機須要去手機店,買電腦須要到電腦城......極大的方便了獲取類的方式。接下來我經過Debug源碼的方式來追一追整個IOC啓動過程的步驟,但願能揭開這個「百貨商場」的神祕面紗。安全

這是咱們debug的入口,用的是最基礎的XML解析的方式。數據結構

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloService service = (HelloService) context.getBean("service");
service.say();
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {
   super(parent); //設置parent父容器
   setConfigLocations(configLocations);//讓ioc容器感知到xml配置文件
   if (refresh) {
      refresh();
   }
}

作的第一步是super(parent),能夠看出IOC容器是具有父子關係的,順便提一下,這個特性在SpringMVC中體現出來了,SpringMVC的容器是 Spring容器的子容器,這樣的結果就是Controller(SpringMVC容器中的Bean)能夠調用Service(Spring容器中的類),而反過來則不行,這樣必定程度保證了類之間的單向關係,以及調用方式不可逆,使得容器更加安全。app

clipboard.png

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 爲刷新作好準備。
      prepareRefresh();
      // 告訴子類刷新內部bean工廠。
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 準備beanfactory,爲使用ioc容器作好準備
      prepareBeanFactory(beanFactory);
      try {
         // 容許beanfactory準備好後作一些事情,擴展點
         postProcessBeanFactory(beanFactory);
         // 將bean註冊在ioc容器
         invokeBeanFactoryPostProcessors(beanFactory);
         // 註冊攔截bean建立的bean處理器。
         registerBeanPostProcessors(beanFactory);
         // 初始化上下文消息
         initMessageSource();
         // 爲這個上下文初始化事件多播器。
         initApplicationEventMulticaster();
         // 初始化特定上下文子類中的其餘特殊bean。
         onRefresh();
         // 檢查listener類並註冊它們
         registerListeners();
         // 實例化全部的lazy-init單例
         finishBeanFactoryInitialization(beanFactory);
         // 最後一步:發佈相應的事件
         finishRefresh();
      }
      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
         // 銷燬已經建立的單例
         destroyBeans();
         // 重置active的值
         cancelRefresh(ex);
         // 將異常傳播給調用者
         throw ex;
      }
      finally {
         //清空一些元數據的內存,這些元數據生成了單例模式後就再也用不到了
         resetCommonCaches();
      }
   }
}

這裏是ioc容器的誕生點 createBeanFactory()框架

protected final void refreshBeanFactory() throws BeansException {
......

      DefaultListableBeanFactory beanFactory = createBeanFactory();
......
      loadBeanDefinitions(beanFactory);
......
}

再看看loadBeanDefinitions()方法 ,這裏解釋下什麼是BeanDefinition (全部的Bean在Spring容器中的數據結構都是BeanDefinition,其中包含了跟這個bean相關的全部信息)beanDefinitionReader能夠看作是一個IOC容器bean的生產者,能夠從外部環境(xml,註解等)獲取到bean的信息並裝載進去,這個方法對beanDefinitionReader 設置了ResourceLoader,EnitityResolver等等對解析xml文件很重要的類,繼續Debug看。ide

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);
}

ResourceLoader會去解析xml文件,將每一個xml中的每一個元素都解析而後返回一個DOM的文檔樹便於後續操做。post

clipboard.png

接着會執行prepareBeanFactory方法,這個方法相似一個制定ioc規則的方法,讓哪些接口的bean不註冊進去,哪些接口的bean註冊進去優化

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   beanFactory.setBeanClassLoader(getClassLoader());
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

以後會對實現了BeanFactoryPostProcessor接口的類處理,該擴展點容許在(容器已經初始完成,可是bean尚未初始化這部分時間進行擴展),體現了Spring的擴展性。

clipboard.png

又看到了一個擴展點,BeanPostProcessor,該擴展點容許在bean 初始化以前或者以後的時候進行擴展

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

接下來回去預實例化沒有設置lazy-init的類

beanFactory.preInstantiateSingletons();

進入這個方法體,在debug已經能夠看到本身設置的bean的id值了

clipboard.png

clipboard.png

能夠看到除了類以外還有scope,lazyInit,primary等屬性

clipboard.png

這兒走了一遍getBean的邏輯,不過由於沒有初始化,去到的實例都是null,接着會標記即將建立的bean,並將其緩存

/**
 標記已建立的(或即將建立的)指定bean。
這容許bean工廠優化其緩存重複。
建立指定的bean。
 * @param beanName the name of the bean
 */
protected void markBeanAsCreated(String beanName) {
   if (!this.alreadyCreated.contains(beanName)) {
      synchronized (this.mergedBeanDefinitions) {
         if (!this.alreadyCreated.contains(beanName)) {
            // Let the bean definition get re-merged now that we're actually creating
            // the bean... just in case some of its metadata changed in the meantime.
            clearMergedBeanDefinition(beanName);
            this.alreadyCreated.add(beanName);
         }
      }
   }
}

立刻進入實例化bean的代碼,其中createBean()是重點

// Create bean instance.
if (mbd.isSingleton()) {
   sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
      @Override
      public Object getObject() throws BeansException {
         try {
            return createBean(beanName, mbd, args);  
         }
         catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throw ex;
         }
      }
   });

追了好幾層終於看到,bean是經過反射實例化的。

Class<?> resolvedClass = ClassUtils.forName(className, classLoader);

若是是singleton,直接從map裏面取,若是沒有則經過反射生成,放進map中而後返回,若是是prototype則每次獲取都會實例化,返回一個新的。

if (mbd.isSingleton()) {
   sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
      @Override
      public Object getObject() throws BeansException {
         try {
            return createBean(beanName, mbd, args);
         }
         catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throw ex;
         }
      }
   });
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      beforePrototypeCreation(beanName);
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
      afterPrototypeCreation(beanName);
   }
   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

這就是緩存單例bean的map

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

總結

ResourceLoader對xml文檔樹進行讀取解析生成Resource文件,Resource文件封裝了對xml文件的IO操做,而後BeanDefinitionReader會對Resource文件讀取並生成BeanDefinition放在BeanDefinitionRegistry裏面,事後beanFactoryPostProcesser會解析佔位符,而後SimpleInstantiationStrategy會經過反射實例化,而後BeanWrapper會對非lazy-init的bean進行賦值,在getBean的時候IOC容器經過Map緩存的方式來達到單例的效果。

相關文章
相關標籤/搜索