首页 > 编程语言 >Spring IOC源码(三):IOC容器之 创建容器

Spring IOC源码(三):IOC容器之 创建容器

时间:2022-12-11 18:46:00浏览次数:62  
标签:容器 beanFactory 对象 加载 源码 解析 IOC beanDefinition

1、源码解析

  obtainFreshBeanFactory()方法包含了 Spring的IOC容器 - DefaultListableBeanFactory对象的创建、解析配置文件中的bean信息加载至容器中。
1 // 创建容器对象DefaultListableBeanFactory,加载xml配置文件的属性值到当前工厂中
2 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

1.1、初始化容器 - refreshBeanFactory()

  refreshBeanFactory()方法由AbstractApplicationContext的子类AbstractRefreshableApplicationContext具体实现,初始化容器-beanFactory。
1 // 刷新内部工厂
2 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
3    // 初始化BeanFactory,并读取XML文件,将得到的BeanFactory记录在当前实体的属性中
4    refreshBeanFactory();
5    // 返回当前实体的beanFactory属性
6    return getBeanFactory();
7 }
refreshBeanFactory()的整体流程:

1、创建容器beanFactory

  创建DefaultListableBeanFactory对象的容器 - beanFactory(忽略BeanNameAware、BeanFactoryAware、BeanClassLoaderAware接口实现类);

2、为beanFactory填充属性

  customizeBeanFactory(beanFactory)是AbstractRefreshableApplicationContext中的方法, 为beanFactory设置属性。
 1 // 为beanFactory填充属性
 2 protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
 3    // 如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性,是否允许覆盖同名称的不同定义的对象
 4    if (this.allowBeanDefinitionOverriding != null) {
 5       beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
 6    }
 7    // 如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,是否允许bean之间存在循环依赖
 8    if (this.allowCircularReferences != null) {
 9       beanFactory.setAllowCircularReferences(this.allowCircularReferences);
10    }
11 }
  allowBeanDefinitionOverriding 与allowCircularReferences 是在createBeanFactory(beanFactory);中做的赋值操作。allowCircularReferences 是在创建DefaultListableBeanFactory对象做的初始化,默认值为true。
1 // 是否允许名称相同但beanDefinition不同的对象被覆盖
2 private boolean allowBeanDefinitionOverriding = true;

3、获取beanDefinition

  解析配置文件中定义的标签信息: 默认标签解析;自定义标签解析。loadBeanDefinitions(beanFactory);加载bean定义信息。

 1 // 通过XmlBeanDefinitionReader加载beanDefinition
 2 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
 3    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
 4    // 创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中
 5    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
 6 
 7    // 为beanDefinitionReader设置环境对象
 8    beanDefinitionReader.setEnvironment(this.getEnvironment());
 9    beanDefinitionReader.setResourceLoader(this);
10    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
11 
12    // 初始化beanDefinitionReader对象,并设置配置文件是否要进行验证
13    initBeanDefinitionReader(beanDefinitionReader);
14    // 加载BeanDefinitions
15    loadBeanDefinitions(beanDefinitionReader);
16 }
  上述代码是AbstractXmlApplicationContext中的方法,创建了bean定义信息读取器,为读取器填充属性,最终会调用XmlBeanDefinitionReader中的loadBeanDefinitions()方法,核心伪代码如下:
 1 // 加载beanDefinition信息
 2 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
 3 
 4    // 通过属性来记录已经加载的资源
 5    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
 6    if (!currentResources.add(encodedResource)) {
 7       throw new BeanDefinitionStoreException(
 8             "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
 9    }
10    // 从encodedResource中获取已经封装的Resource对象, 再获取Resource对象的inputStream流信息
11    try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
12       InputSource inputSource = new InputSource(inputStream);
13       if (encodedResource.getEncoding() != null) {
14          inputSource.setEncoding(encodedResource.getEncoding());
15       }
16       // 加载beanDefinition核心逻辑,实际从指定的xml中加载beanDefinition
17       return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
18    }
19    catch (IOException ex) {
20       throw new BeanDefinitionStoreException(
21             "IOException parsing XML document from " + encodedResource.getResource(), ex);
22    }
23    finally {
24       // 移除已经加载的资源
25       currentResources.remove(encodedResource);
26       if (currentResources.isEmpty()) {
27          this.resourcesCurrentlyBeingLoaded.remove();
28       }
29    }
30 }
  可以看到这一步还是加载beanDefinition的准备工作,获取Resource对象的输入流inputStream,封装输入流并进入加载beanDefinition的核心逻辑doLoadBeanDefinitions()。
 1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
 2       throws BeanDefinitionStoreException {
 3 
 4    try {
 5       // 获取xml文件的document对象,这个解析过程是由documentLoader完成的,
 6       Document doc = doLoadDocument(inputSource, resource);
 7       // 根据文档的节点信息封装成一个个的BeanDefinition对象
 8       int count = registerBeanDefinitions(doc, resource);
 9       if (logger.isDebugEnabled()) {
10          logger.debug("Loaded " + count + " bean definitions from " + resource);
11       }
12       return count;
13    }
14    .....
15    catch (Throwable ex) {
16       throw new BeanDefinitionStoreException(resource.getDescription(),
17             "Unexpected exception parsing XML document from " + resource, ex);
18    }
19 }
  该步骤主要是注册bean定义信息的准备工作,获取配置文件的document对象,通过String[](配置文件集合) -string(配置文件)-Resource[]- resource,最终开始将resource读取成一个document文档。
 1 // 创建document对象的读取器
 2 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
 3    // 对xml的beanDefinition进行解析
 4    // 创建BeanDefinitionDocumentReader对象
 5    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
 6    int countBefore = getRegistry().getBeanDefinitionCount();
 7    // 通过spring-beans的XSD或DTD实现beanDefinition具体的解析过程
 8    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
 9    return getRegistry().getBeanDefinitionCount() - countBefore;
10 }
  该步是注册bean定义信息的准备工作,获取document对象读取器。
1 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
2    this.readerContext = readerContext;
3    // 注册定义在<bean/>标签的每一个beanDefinition
4    doRegisterBeanDefinitions(doc.getDocumentElement());
5 }
  doRegisterBeanDefinitions()是将BeanDefinition对象注册进容器的核心逻辑,核心伪代码如下
 1 public static final String PROFILE_ATTRIBUTE = "profile";
 2 public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
 3 
 4 // 注册beanDefinitionn的核心处理逻辑
 5 protected void doRegisterBeanDefinitions(Element root) {
 6    BeanDefinitionParserDelegate parent = this.delegate;
 7    // 初始化解析beanDefinition的委托类
 8    this.delegate = createDelegate(getReaderContext(), root, parent);
 9    // ...
10    // 解析beanDefinition前的处理
11    preProcessXml(root);
12    // 解析beanDefinition信息
13    parseBeanDefinitions(root, this.delegate);
14    // 解析beanDefinition后的处理
15    postProcessXml(root);
16 
17    this.delegate = parent;
18 }
  doRegisterBeanDefinitions()中的核心步骤 parseBeanDefinitions(root, this.delegate);,preProcessXml和postrocessXml有子类拓展实现,下面来看看DefaultBeanDefinitionDocumentReader中的解析方法parseBeanDefinitions()。
 1 // 解析bean定义信息
 2 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 3     // 是否为默认命名空间
 4     if (delegate.isDefaultNamespace(root)) {
 5       NodeList nl = root.getChildNodes();
 6       for (int i = 0; i < nl.getLength(); i++) {
 7          Node node = nl.item(i);
 8          if (node instanceof Element) {
 9             Element ele = (Element) node;
10             // 解析默认命名空间元素,如<bean>标签
11             if (delegate.isDefaultNamespace(ele)) {
12                parseDefaultElement(ele, delegate);
13             }
14             // 解析自定义命名空间元素,如<aop>相关标签
15             else {
16                delegate.parseCustomElement(ele);
17             }
18          }
19       }
20    }
21    else {
22       delegate.parseCustomElement(root);
23    }
24 }
  parseBeanDefinitions()解析document对象文档树中的默认标签、自定义标签。关于beanDefinition的具体解析,我们放在下一章节介绍。

1.2、初始化容器 - refreshBeanFactory()

  AbstractApplicationContext中的refreshBeanFactory方法由其子类ConfigurableListableBeanFactory实现,返回的是在refreshBeanFactory()方法中赋值的beanFactory。

2、总结

obtainFreshBeanFactory()核心流程总结

2.1、创建beanFactory容器

  创建容器DefaultListableBeanFactory对象,同时初始化容器中的1allowBeanDefinitionOverriding、allowCircularReferences等属性。

2.2、loadBeanDefinition加载bean定义核心流程

·创建BeanDefinitionReader,bean定义读取器对象,并将容器beanFactory回调至读取器中; ·为BeanDefinitionReader设置环境对象,资源解析器; ·创建document对象   从配置文件路径location数组String[] -> Resource对象数组 -> Resource对象封装为InputStream输入流 -> InputSource对象 -> document对象 ·创建documentReader对象; ·创建bean定义解析代理BeanDefinitionParserDelegate对象; ·解析document各文档节点,获取beanDefinition并加载至容器中。 ·默认标签解析 ·自定义标签解析  

标签:容器,beanFactory,对象,加载,源码,解析,IOC,beanDefinition
From: https://www.cnblogs.com/RunningSnails/p/16974122.html

相关文章