Spring IOC源码学习笔记(一)默认标签的解析及BeanDifinition的注册

  1. 容器基本用法
    测试类
public class MyTestBean {
    private String testStr = "testStr";

    public String getTestStr() {
        return testStr;
    }

    public void setTestStr(String testStr) {
        this.testStr = testStr;
    }
}

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="myTestBean" class="com.xxy.core.ioc.MyTestBean"/>
</beans>

测试代码

 @Test
 public void test() {
      BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
      MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
      Assert.assertEquals("testStr", bean.getTestStr());
  }
  1. 源码学习
    从测试代码开始,第一行BeanFactory bf = new XmlBeanFactory(new ClassPathResource(“beanFactoryTest.xml”));
    首先看ClassPathResource类:
	private final String path;
    @Nullable
    private ClassLoader classLoader;
    @Nullable
    private Class<?> clazz;

    public ClassPathResource(String path) {
        this(path, (ClassLoader)null);
    }

    public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
        Assert.notNull(path, "Path must not be null");
        String pathToUse = StringUtils.cleanPath(path);
        if (pathToUse.startsWith("/")) {
            pathToUse = pathToUse.substring(1);
        }

        this.path = pathToUse;
        this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
    }

    public ClassPathResource(String path, @Nullable Class<?> clazz) {
        Assert.notNull(path, "Path must not be null");
        this.path = StringUtils.cleanPath(path);
        this.clazz = clazz;
    }

一共有三个成员和三个构造方法,构造方法主要是对路径的检查和成员的赋值。
接下来进入XmlBeanFactory类:

public class XmlBeanFactory extends DefaultListableBeanFactory {
    private final XmlBeanDefinitionReader reader;

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        this.reader.loadBeanDefinitions(resource);
    }
}

两个构造方法,单参构造传入Resource之后调用双参构造,进入双参构造方法,首先是调用父类方法对parentBeanFactory进行赋值,单参构造parentBeanFactory直接设为null,暂时没有尝试使用双参构造。接下来初始化XmlBeanDefinitionReader并进行赋值,XmlBeanDefinitionReader的初始化过程并不是这里的重点,不进入源码进行分析了。XmlBeanDefinitionReader初始化完毕后,调用loadBeanDefinitions方法,传入resource:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions(new EncodedResource(resource));
}

可以看到首先通过EncodedResource对Resource进行封装,接着进入到loadBeanDefinitions(EncodedResource encodedResource)方法:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
      Assert.notNull(encodedResource, "EncodedResource must not be null");
      if (this.logger.isTraceEnabled()) {
          this.logger.trace("Loading XML bean definitions from " + encodedResource);
      }
//记录已经加载的资源
      Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
      if (currentResources == null) {
      //初始化HashSet
          currentResources = new HashSet(4);
          this.resourcesCurrentlyBeingLoaded.set(currentResources);
      }
//添加失败则抛出异常
      if (!((Set)currentResources).add(encodedResource)) {
          throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
      } else {
          int var5;
          //从encodedResource获取Resource对象中的InputStream对象
          try {
              InputStream inputStream = encodedResource.getResource().getInputStream();

              try {
              //通过InputSource类对inputStream进行封装
                  InputSource inputSource = new InputSource(inputStream);
                  if (encodedResource.getEncoding() != null) {
                      inputSource.setEncoding(encodedResource.getEncoding());
                  }
//真正进入核心逻辑
                  var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
              } finally {
              //关闭输入流
                  inputStream.close();
              }
          } catch (IOException var15) {
              throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
          } finally {
              ((Set)currentResources).remove(encodedResource);
              if (((Set)currentResources).isEmpty()) {
                  this.resourcesCurrentlyBeingLoaded.remove();
              }

          }

          return var5;
      }
  }

进入doLoadBeanDefinitions方法:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
     try {
         Document doc = this.doLoadDocument(inputSource, resource);
         int count = this.registerBeanDefinitions(doc, resource);
         if (this.logger.isDebugEnabled()) {
             this.logger.debug("Loaded " + count + " bean definitions from " + resource);
         }

         return count;
     } catch (BeanDefinitionStoreException var5) {
         throw var5;
     } catch (SAXParseException var6) {
         throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);
     } catch (SAXException var7) {
         throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);
     } catch (ParserConfigurationException var8) {
         throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);
     } catch (IOException var9) {
         throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);
     } catch (Throwable var10) {
         throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);
     }
 }

首先获取Document,然后根据返回的Document实例注册bean信息。doLoadDocument部分略过,直接进入registerBeanDefinitions方法:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//首先实例化documentReader
     BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
     //实例化BeanDefinitionReader时会传入BeanDefinitionRegistry
     //记录BeanDefinition的加载个数
     int countBefore = this.getRegistry().getBeanDefinitionCount();
     //开始注册bean
     documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
     //返回本次加载BeanDefinition的个数
     return this.getRegistry().getBeanDefinitionCount() - countBefore;
 }

进入registerBeanDefinitions方法,这个方法是定义在BeanDefinitionDocumentReader接口中的,这个接口只有唯一的实现类DefaultBeanDefinitionDocumentReader:

	public static final String BEAN_ELEMENT = "bean";
    public static final String NESTED_BEANS_ELEMENT = "beans";
    public static final String ALIAS_ELEMENT = "alias";
    public static final String NAME_ATTRIBUTE = "name";
    public static final String ALIAS_ATTRIBUTE = "alias";
    public static final String IMPORT_ELEMENT = "import";
    public static final String RESOURCE_ATTRIBUTE = "resource";
    public static final String PROFILE_ATTRIBUTE = "profile";
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        this.doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    protected void doRegisterBeanDefinitions(Element root) {
    //专门处理解析
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        //判断是否是默认的命名空间
        if (this.delegate.isDefaultNamespace(root)) {
        //处理profile关键字
            String profileSpec = root.getAttribute("profile");
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }

                    return;
                }
            }
        }
		//解析前处理
        this.preProcessXml(root);
        this.parseBeanDefinitions(root, this.delegate);
        //解析后处理
        this.postProcessXml(root);
        this.delegate = parent;
    }

首先可以发现这个类的成员定义了在写XML文件时的关键字。然后看doRegisterBeanDefinitions方法,其中profile是用于配置文件中部署两套环境来使用于生产环境和开发环境,这样可以方便的进行环境切换,最常用的就是更换不同的数据库。解析前后处理的代码都是空的,留给子类实现,spring并没有实现它的子类代码。因此这段代码的重点进入parseBeanDefinitions方法:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element)node;
                if (delegate.isDefaultNamespace(ele)) {
                    this.parseDefaultElement(ele, delegate);
                } else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    } else {
        delegate.parseCustomElement(root);
    }

}

做过xml文件解析的应该很容易看懂这就是对xml文件标签的遍历解析,其中有对是否是默认命名空间的判断,spring中有两大类bean声明,一种是默认的,一种是自定义的,代码的逻辑还是很清晰的。自定义标签的解析这里不进行分析,进入默认标签的解析,也就是parseDefaultElement方法:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//处理import标签
    if (delegate.nodeNameEquals(ele, "import")) {
        this.importBeanDefinitionResource(ele);
        //处理alias标签
    } else if (delegate.nodeNameEquals(ele, "alias")) {
        this.processAliasRegistration(ele);
        //处理bean标签
    } else if (delegate.nodeNameEquals(ele, "bean")) {
        this.processBeanDefinition(ele, delegate);
        //处理beans标签
    } else if (delegate.nodeNameEquals(ele, "beans")) {
        this.doRegisterBeanDefinitions(ele);
    }

}

进入对bean标签的解析流程:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//对标签中各种属性的解析及封装 
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
    //下面这行代码是解决bean使用的是默认标签,但其子元素却使用了自定义标签的配置
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

        try {
        //注册BeanDefinition
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
        } catch (BeanDefinitionStoreException var5) {
            this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
        }
//发出响应通知监听器,spring没有做逻辑处理
        this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }

}

同样不关注自定义标签,上面的代码有两个方法需要注意,首先看parseBeanDefinitionElement方法:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
}

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//解析id属性
    String id = ele.getAttribute("id");
    //解析name属性
    String nameAttr = ele.getAttribute("name");
    //分割name属性
    List<String> aliases = new ArrayList();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
        aliases.addAll(Arrays.asList(nameArr));
    }
//有id属性则beanName为id
    String beanName = id;
    //没有id属性但是有name属性,则第一个name为beanName
    if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
        beanName = (String)aliases.remove(0);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
        }
    }
//检测beanName是否已经被使用
    if (containingBean == null) {
        this.checkNameUniqueness(beanName, aliases, ele);
    }

//进一步解析其他属性
    AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                //如果不存在beanName,则按照spring命名规则生成beanName
                    beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                } else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }

                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                }
            } catch (Exception var9) {
                this.error(var9.getMessage(), ele);
                return null;
            }
        }

        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    } else {
        return null;
    }
}

进入进一步解析属性的parseBeanDefinitionElement方法:

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
//入栈
    this.parseState.push(new BeanEntry(beanName));
    //解析class属性
    String className = null;
    if (ele.hasAttribute("class")) {
        className = ele.getAttribute("class").trim();
    }
//解析parent属性
    String parent = null;
    if (ele.hasAttribute("parent")) {
        parent = ele.getAttribute("parent");
    }

    try {
    //GenericBeanDefinition对BeanDefinition的进一步封装
        AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
        //硬编码解析bean的各种属性
        this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        //提取description
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
        //解析元数据
        this.parseMetaElements(ele, bd);
        //解析lookup-method属性
        this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        //解析replace-method属性
        this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        //解析构造函数
        this.parseConstructorArgElements(ele, bd);
        //解析Property元素
        this.parsePropertyElements(ele, bd);
        //解析Qualifier元素
        this.parseQualifierElements(ele, bd);
        bd.setResource(this.readerContext.getResource());
        bd.setSource(this.extractSource(ele));
        AbstractBeanDefinition var7 = bd;
        return var7;
    } catch (ClassNotFoundException var13) {
        this.error("Bean class [" + className + "] not found", ele, var13);
    } catch (NoClassDefFoundError var14) {
        this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
    } catch (Throwable var15) {
        this.error("Unexpected failure during bean definition parsing", ele, var15);
    } finally {
    //出栈
        this.parseState.pop();
    }

    return null;
}

对于详细的标签解析过程和其他三种标签的解析这里不进行描述,这段代码中可以看出,如果没有发生异常则会返回填充了各种属性之后的GenericBeanDefinition。到此bean标签的解析就完成了。
而在解析完成之后,通过一系列的return返回processBeanDefinition方法,接下来是beanDifinition的注册过程,registerBeanDefinition方法,由BeanDefinitionReaderUtils类实现:

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
//首先获取beanName
    String beanName = definitionHolder.getBeanName();
    //根据beanName注册
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    //注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        String[] var4 = aliases;
        int var5 = aliases.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String alias = var4[var6];
            //注册别名
            registry.registerAlias(beanName, alias);
        }
    }
}

可以看到一共有两种注册方法,第一种是根据beanName进行注册,一种是根据alias进行注册。先看registerBeanDefinition方法,根据register定义在BeanDefinitionRegistry接口中,如果仔细看源码的启动流程可以发现BeanDefinitionRegistry的实现类一般是DefaultListableBeanFactory:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
private volatile List<String> beanDefinitionNames = new ArrayList(256);
//手动注册的单例类名称,按照注册顺序排序
private volatile Set<String> manualSingletonNames = new LinkedHashSet(16);
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
            //注册之前的最后一次校验,主要是对AbstractBeanDefinition中的methodOverrides校验
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var8) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
            }
        }
//beanDefinitionMap是全局变量,处理并发情况
        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
//处理注册已经注册的beanName的情况
        if (existingDefinition != null) {
        //不允许覆盖则抛出异常
            if (!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
//处理允许覆盖的逻辑
            if (existingDefinition.getRole() < beanDefinition.getRole()) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (!beanDefinition.equals(existingDefinition)) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (this.logger.isTraceEnabled()) {
                this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
        //判断BeanFactory 中Bean的创建阶段是否已经开始
            if (this.hasBeanCreationStarted()) {
                Map var4 = this.beanDefinitionMap;
                synchronized(this.beanDefinitionMap) {
                // 加入beanDefinitionMap
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                     创建List<String>
                    List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    //将缓存的beanDefinitionNames和新解析的beanName加入集合
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    //更新集合
                    this.beanDefinitionNames = updatedDefinitions;
                    //从manualSingletonNames中移除
                    this.removeManualSingletonName(beanName);
                }
                //没有开始
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.removeManualSingletonName(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }
//如果有同名的bean,重置
        if (existingDefinition != null || this.containsSingleton(beanName)) {
            this.resetBeanDefinition(beanName);
        }

    }

接下来看alias的注册,registerAlias方法定义在AliasRegistry接口中,DefaultListableBeanFactory是其实现类SimpleAliasRegistry的子类:

private final Map<String, String> aliasMap = new ConcurrentHashMap(16);
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    Map var3 = this.aliasMap;
    synchronized(this.aliasMap) {
    // 如果beanName与别名相同
        if (alias.equals(name)) {
        //移除别名
            this.aliasMap.remove(alias);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
            }
        } else {
         //尝试从缓存中获取别名
            String registeredName = (String)this.aliasMap.get(alias);
            //存在
            if (registeredName != null) {
             //缓存中的别名和beanName相同,不做任何操作,不需要再次注册
                if (registeredName.equals(name)) {
                    return;
                }
//缓存中存在别名,且不允许覆盖,抛出异常
                if (!this.allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'");
                }
            }
//当A->B存在,若再次出现A->C->B,则抛出异常
            this.checkForAliasCircle(name, alias);
            //缓存别名
            this.aliasMap.put(alias, name);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
            }
        }

    }
}

在注册完成之后就会返回processBeanDefinition方法,而processBeanDefinitionfa方法此时也已经完成了,因此完成了对一个bean标签的解析,对标签的解析则是在parseBeanDefinitions方法的循环中执行的,循环结束则意味着xml文件解析完成,所有的beanDifition都以及注册结束。接下来就是一步步返回并完成一些善后工作,比如关闭输入流。

对于默认标签的解析及BeanDifition的注册这里差不多就总结完毕了,如果有什么错误欢迎指正。

参考书籍:Spring源码深度解析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值