spring源码解析bean定义加载一

前言

接着上次的spring上下文加载过程的源码解析

正文

上次主要介绍到刷新beanFactory,找到这个方法org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory的这行代码

@Override
   protected final void refreshBeanFactory() throws BeansException {
//    如果存在beanFactory
      if (hasBeanFactory()) {
//       销毁bean
         destroyBeans();
//       关闭beanFactory
         closeBeanFactory();
      }

bean销毁介绍完了,找到这行代码

closeBeanFactory();
@Override
protected final void closeBeanFactory() {
   synchronized (this.beanFactoryMonitor) {
      if (this.beanFactory != null) {
         this.beanFactory.setSerializationId(null);
         this.beanFactory = null;
      }
   }
}

操作beanFactory是同步的。

找到这行代码,创建banFactory

DefaultListableBeanFactory beanFactory = createBeanFactory();
protected DefaultListableBeanFactory createBeanFactory() {
   return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
@Nullable
   protected BeanFactory getInternalParentBeanFactory() {
//    如果父上下文是配置上下文
      return (getParent() instanceof ConfigurableApplicationContext) ?
            ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
   }

返回到这个方法

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

customizeBeanFactory(beanFactory);
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//    是否允许bean定义覆盖
      if (this.allowBeanDefinitionOverriding != null) {
         beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
      }
//    是否允许bean之间循环引用
      if (this.allowCircularReferences != null) {
         beanFactory.setAllowCircularReferences(this.allowCircularReferences);
      }
   }

返回到这个方法

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

loadBeanDefinitions(beanFactory);

这一行代码,加载bean定义。

进入到这个方法

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)通过XmlBeanDefinitionReader加载bean定义。

@Override
   protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
      // Create a new XmlBeanDefinitionReader for the given BeanFactory.为给定的BeanFactory创建一个新的XmlBeanDefinitionReader。
      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

      // Configure the bean definition reader with this context's
      // resource loading environment.使用该上下文的资源加载环境配置bean定义阅读器。
      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.允许子类提供读取器的自定义初始化,然后继续加载bean定义。
      initBeanDefinitionReader(beanDefinitionReader);
//    加载bean定义
      loadBeanDefinitions(beanDefinitionReader);
   }
//     加载资源
      beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
public ResourceEntityResolver(ResourceLoader resourceLoader) {
   super(resourceLoader.getClassLoader());
   this.resourceLoader = resourceLoader;
}

进入调用了父类构造器的方法

public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
//    创建DTD解析器
      this.dtdResolver = new BeansDtdResolver();
//    创建schema解析器
      this.schemaResolver = new PluggableSchemaResolver(classLoader);
   }

可以看到解析的是这个DTD

public class BeansDtdResolver implements EntityResolver {

// dtd解析
   private static final String DTD_EXTENSION = ".dtd";

   private static final String DTD_NAME = "spring-beans";
public PluggableSchemaResolver(@Nullable ClassLoader classLoader) {
   this.classLoader = classLoader;
   this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
}

org.springframework.beans.factory.xml.PluggableSchemaResolver

//  spring.schemas解析,这个路径下面的schemas都会被解析 META-INF/spring.schemas
   public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";

从这个地方加载的schema

找到这个方法

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)的这行代码

//     初始化bean定义
      initBeanDefinitionReader(beanDefinitionReader);
//     加载bean定义
      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);
   }
}
//     获取配置文件路径
      String[] configLocations = getConfigLocations();
@Nullable
protected String[] getConfigLocations() {
   return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}

我们看下configLocations变量在哪里赋值的

public void setConfigLocation(String location) {
   setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}

我们看下location变量在哪里赋值的

找到了这个方法org.springframework.web.context.ContextLoader#configureAndRefreshWebApplicationContext

String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
   wac.setConfigLocation(configLocationParam);
}
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";

是从servlet容器启动时初始化的参数配置中获取的

返回到这个方法

org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setConfigLocation

public void setConfigLocation(String location) {
   setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}

看下这个常量org.springframework.context.ConfigurableApplicationContext#CONFIG_LOCATION_DELIMITERS

String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

bean定义配置文件可以是,或;或空格或换行符分开都可以。

进入到这个方法

org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setConfigLocations

public void setConfigLocations(@Nullable String... locations) {
   if (locations != null) {
      Assert.noNullElements(locations, "Config locations must not be null");
      this.configLocations = new String[locations.length];
      for (int i = 0; i < locations.length; i++) {
         this.configLocations[i] = resolvePath(locations[i]).trim();
      }
   }
   else {
      this.configLocations = null;
   }
}
//           解析配置文件后把配置文件路径放到spring上下文中
            this.configLocations[i] = resolvePath(locations[i]).trim();

bean定义配置文件中如果有占位符就替换占位符

protected String resolvePath(String path) {
   return getEnvironment().resolveRequiredPlaceholders(path);
}
@Override
   public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
      if (this.strictHelper == null) {
         this.strictHelper = createPlaceholderHelper(false);
      }
//    替换占位符
      return doResolvePlaceholders(text, this.strictHelper);
   }

返回到这个方法

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)的这一行代码

//        加载bean定义
         reader.loadBeanDefinitions(configLocations);
@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;
}

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String)

@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
   return loadBeanDefinitions(location, null);
}

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)

这段代码

//     从classpath下面加载
      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);
         }
      }

找到这行代码

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

进入到这个方法

org.springframework.core.io.support.PathMatchingResourcePatternResolver#getResources

@Override
   public Resource[] getResources(String locationPattern) throws IOException {
      Assert.notNull(locationPattern, "Location pattern must not be null");
//    配置路径以classpath*:开头
      if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
         // a class path resource (multiple resources for same name possible)
         if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
            // a class path resource pattern 从classpath*路径下匹配的的jar,war包等文件中查找配置文件
            return findPathMatchingResources(locationPattern);
         }
         else {
            // all class path resources with the given name 从classpath下面加载jar、war文件中的配置文件
            return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
         }
      }
      else {
         // Generally only look for a pattern after a prefix here,
         // and on Tomcat only after the "*/" separator for its "war:" protocol.
         int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
               locationPattern.indexOf(':') + 1);
         if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
            // a file pattern
            return findPathMatchingResources(locationPattern);
         }
         else {
            // a single resource with the given name
            return new Resource[] {getResourceLoader().getResource(locationPattern)};
         }
      }
   }

返回到这个方法

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)

递归调用
            int loadCount = loadBeanDefinitions(resources);
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int counter = 0;
   for (Resource resource : resources) {
      counter += loadBeanDefinitions(resource);
   }
   return counter;
}

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)

@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   return loadBeanDefinitions(new EncodedResource(resource));
}

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
      Assert.notNull(encodedResource, "EncodedResource must not be null");
      if (logger.isInfoEnabled()) {
         logger.info("Loading XML bean definitions from " + encodedResource.getResource());
      }

//    resourcesCurrentlyBeingLoaded threadLocal保证线程安全
      Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
      if (currentResources == null) {
         currentResources = new HashSet<>(4);
         this.resourcesCurrentlyBeingLoaded.set(currentResources);
      }
      if (!currentResources.add(encodedResource)) {
         throw new BeanDefinitionStoreException(
               "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
      }
      try {
         InputStream inputStream = encodedResource.getResource().getInputStream();
         try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
               inputSource.setEncoding(encodedResource.getEncoding());
            }
//          加载bean定义
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
         }
         finally {
            inputStream.close();
         }
      }
      catch (IOException ex) {
         throw new BeanDefinitionStoreException(
               "IOException parsing XML document from " + encodedResource.getResource(), ex);
      }
      finally {
         currentResources.remove(encodedResource);
         if (currentResources.isEmpty()) {
//          防止内存泄漏
            this.resourcesCurrentlyBeingLoaded.remove();
         }
      }
   }

找到这行代码

//           加载bean定义
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

内容太多,下篇文章接着解析。

最后

本次介绍到这里,以上内容仅供参考。大家从spring源码解析第一篇文章开始看,更容易点,否则可读性可能不台好,因为spring源码体系太庞大,不太好归类,按每篇文章的篇幅不太好拆分。

扫码关注

进群讨论

快到碗里来

!

猜你喜欢

转载自my.oschina.net/u/3775437/blog/1810423