Spring5對比Spring3.2源碼之容器的基本實現

最近看了《Spring源碼深度解析》,該書是基於Spring3.2版本的,其中關於第二章容器的基本實現部分,目前spring5的實現方式已有較大改變。java

Spring3.2的實現:spring

public void testSimpleLoad(){

    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring/application-context.xml"));

    UserService userService = (UserService)beanFactory.getBean("userService");

}

容器的基礎XmlBeanFactory已經被廢棄(@Deprecated)。app

Spring5.0的實現方式有兩種:ide

第一種是經過ClassPathXmlApplicationContext實現的,也是經常使用的一種。函數

public void classPath(){

    ApplicationContext context = new ClassPathXmlApplicationContext("spring/application-context.xml");

    UserService userService = (UserService) context.getBean("userService");

    userService.update();

}

第二種是經過FileSystemXmlApplicationContext實現的。post

public void fileSystem(){

    ApplicationContext context = new FileSystemXmlApplicationContext("target/classes/spring/application-context.xml");

    UserService userService = (UserService) context.getBean("userService");

    userService.update();

}

兩種方式的區別在於尋找配置文件的根路徑的不一樣。下面我就以ClassPathXmlApplicationContext對比Spring3.2的XmlBeanFactory是如何加載配置文件xml中咱們的Bean的。this

ClassPathXmlApplicationContext的構造函數:spa

public ClassPathXmlApplicationContext(

      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

      throws BeansException {



   super(parent);

   setConfigLocations(configLocations);

   if (refresh) {

      refresh();

   }

}

關鍵方法refresh()的源碼debug

@Override

public void refresh() throws BeansException, IllegalStateException {

   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();
      // 告訴子類刷新內部bean工廠
      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();
      }
   }
}

構建Bean容器的步驟就在這個refresh()方法中。其中obtainFreshBeanFactory();刷新Bean工廠。code

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

   refreshBeanFactory();

   ConfigurableListableBeanFactory beanFactory = getBeanFactory();

   if (logger.isDebugEnabled()) {

      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);

   }

   return beanFactory;

}
protected final void refreshBeanFactory() throws BeansException {

   if (hasBeanFactory()) {

      destroyBeans();

      closeBeanFactory();

   }

   try {

      DefaultListableBeanFactory beanFactory = createBeanFactory();

      beanFactory.setSerializationId(getId());

      customizeBeanFactory(beanFactory);

      loadBeanDefinitions(beanFactory);

      synchronized (this.beanFactoryMonitor) {

         this.beanFactory = beanFactory;

      }

   }

   catch (IOException ex) {

      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);

   }

}

看到這個DefaultListableBeanFactory了嗎?Spring3.2的實現方式的XmlBeanFactory就是繼承自DefaultListableBeanFactory,是整個bean加載的核心部分,具體能夠參考《Spring源碼深度解析》。

進入loadBeanDefinitions(beanFactory);

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

}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

   Resource[] configResources = getConfigResources();

   if (configResources != null) {

      reader.loadBeanDefinitions(configResources);

   }

   String[] configLocations = getConfigLocations();

   if (configLocations != null) {

      reader.loadBeanDefinitions(configLocations);

   }

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

}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {

   ResourceLoader resourceLoader = getResourceLoader();

   if (resourceLoader == null) {

      throw new BeanDefinitionStoreException(

            "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");

   }



   if (resourceLoader instanceof ResourcePatternResolver) {

      // Resource pattern matching available.

      try {

         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

         int loadCount = loadBeanDefinitions(resources);

         if (actualResources != null) {

            for (Resource resource : resources) {

               actualResources.add(resource);

            }

         }

         if (logger.isDebugEnabled()) {

            logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");

         }

         return loadCount;

      }

      catch (IOException ex) {

         throw new BeanDefinitionStoreException(

               "Could not resolve bean definition resource pattern [" + location + "]", ex);

      }

   }

   else {

      // Can only load single resources by absolute URL.

      Resource resource = resourceLoader.getResource(location);

      int loadCount = loadBeanDefinitions(resource);

      if (actualResources != null) {

         actualResources.add(resource);

      }

      if (logger.isDebugEnabled()) {

         logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");

      }

      return loadCount;

   }

}
@Override

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

   return loadBeanDefinitions(new EncodedResource(resource));

}

到此這個方法就和《Spring源碼深度機械》一書加載Bean的介紹一致了,後續加載過程可參考此書。

相關文章
相關標籤/搜索