Spring架构及源码分析(三)Beandefination

Spring架构及源码分析(三)Beandefination,第1张

Spring架构及源码分析(三)Beandefination

         在上篇文章中,我们讨论了 refresh 的前四个方法,主要是对 ApplicationContext 上下文启动做一些准备工作。接下来对 invokeBeanFactoryPostProcessors 方法进行讨论,但该方法涉及 Spring 中一个非常重要的概念: BeanDefinition,所以,这里先对 BeanDefinition 进行讨论,这样也有利于完善 Spring 的知识体系。

        首先看一下Spring一个大概的流程处理过程。

        读取XML-> 解析XML封装成DOC对象 ->  DOC对象转换成Spring beanDefinition对象 -> 转换成metaData对象 ->  获取metaData对象开始创建bean

        Spring容器启动的过程中,会将Bean定义信息解析成Spring内部的BeanDefinition结构。

        Bean信息定义4种方式

                1.API方式

                2.XML文件方式

                3.注解方式

                        类上标注@Compontent注解来定义一个bean

                        配置类中使用@Bean注解来定义bean

                4.properties文件的方式

        不管是是通过xml配置文件的标签,还是通过注解配置的@Bean,还是@Compontent标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等 *** 作。

        你可以把BeanDefinition丢给Bean工厂,然后Bean工厂就会根据这个信息帮你生产一个Bean实例。

        BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean,一个 BeanDefinition 描述了一个 Bean 实例,实例包含属性值、构造方法参数值以及更多实现信息。下面以XML文件配置方式从源码上跟一下BeanDefinition的注册过程。

       1. 首先在ClassPathXmlApplicationContext设置了xml文件的位置,然后调用AbstractApplicationContext的refresh()方法。

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {
    super(parent);
    //创建解析器,解析configLocations
    setConfigLocations(configLocations);
    if (refresh) {
    // 核心方法
      refresh();
    }
  }

         2.AbstractApplicationContext里obtainFreshBeanFactory()方法解析xml标签封装成BeanDefinition对象。

// AbstractApplicationContext.java
  
  @Override
  public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      
      //为容器初始化做准备
      prepareRefresh();
 
      
      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
      ......
    }
  }
// AbstractApplicationContext.java
 
@Override
  protected final void refreshBeanFactory() throws BeansException {
 
......
    try {
      //创建DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
 
      //设置是否可以循环依赖 allowCircularReferences
      //是否允许使用相同名称重新注册不同的bean实现.
      customizeBeanFactory(beanFactory);
 
      //解析xml,并把xml中的标签封装成BeanDefinition对象
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
      }
    }
......
  }
// AbstractXmlApplicationContext.java
@Override
  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

    //创建xml的解析器,这里是一个委托模式
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
 
 
    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(this.getEnvironment());
 
 
    //这里传一个this进去,因为ApplicationContext是实现了ResourceLoader接口的
    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);
  }
// AbstractXmlApplicationContext.java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
    }
    //获取需要加载的xml配置文件
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
    }
  }
// AbstractBeanDefinitionReader.java
@Override
  public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int count = 0;
    //配置文件有多个,加载多个配置文件
    for (String location : locations) {
      count += loadBeanDefinitions(location);
    }
    return count;
  }
// AbstractBeanDefinitionReader.java
public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
      throw new BeanDefinitionStoreException(
          "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
    }
 
 
    if (resourceLoader instanceof ResourcePatternResolver) {
      // Resource pattern matching available.
      try {
        //把字符串类型的xml文件路径,形如:classpath*:user*-context.xml,转换成Resource对象类型,其实就是用流
        //的方式加载配置文件,然后封装成Resource对象,不重要,可以不看
        Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
 
        //主要看这个方法
        int count = loadBeanDefinitions(resources);
        if (actualResources != null) {
          Collections.addAll(actualResources, resources);
        }
        if (logger.isTraceEnabled()) {
          logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
        }
        return count;
      }
      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 count = loadBeanDefinitions(resource);
      if (actualResources != null) {
        actualResources.add(resource);
      }
      if (logger.isTraceEnabled()) {
        logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
      }
      return count;
    }
  }
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isTraceEnabled()) {
      logger.trace("Loading XML bean definitions from " + encodedResource);
    }
 
 
    Set 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 {
      //获取Resource对象中的xml文件流对象
      InputStream inputStream = encodedResource.getResource().getInputStream();
      try {
        //InputSource是jdk中的sax xml文件解析对象
        InputSource inputSource = new InputSource(inputStream);
        if (encodedResource.getEncoding() != null) {
          inputSource.setEncoding(encodedResource.getEncoding());
        }
        //主要看这个方法 
        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();
      }
    }
  }
// 开始将XML解析封装为document对象
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
 
    try {
      //把inputSource 封装成document文件对象,这是jdk的API
      document doc = doLoaddocument(inputSource, resource);
 
      //主要看这个方法,根据解析出来的document对象,拿到里面的标签元素封装成BeanDefinition
      int count = registerBeanDefinitions(doc, resource);
      if (logger.isDebugEnabled()) {
        logger.debug("Loaded " + count + " bean definitions from " + resource);
      }
      return count;
    }
    catch (BeanDefinitionStoreException ex) {
      throw ex;
    }
    catch (SAXParseException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
          "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    }
    catch (SAXException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
          "XML document from " + resource + " is invalid", ex);
    }
    catch (ParserConfigurationException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
          "Parser configuration exception parsing XML from " + resource, ex);
    }
    catch (IOException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
          "IOException parsing XML document from " + resource, ex);
    }
    catch (Throwable ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
          "Unexpected exception parsing XML document from " + resource, ex);
    }
  }
public int registerBeanDefinitions(document doc, Resource resource) throws BeanDefinitionStoreException {
    //又来一记委托模式,BeanDefinitiondocumentReader委托这个类进行document的解析
    BeanDefinitiondocumentReader documentReader = createBeanDefinitiondocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    //主要看这个方法,createReaderContext(resource) XmlReaderContext上下文,封装了XmlBeanDefinitionReader对象
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
  }
// DefaultBeanDefinitiondocumentReader.java
  @Override
  public void registerBeanDefinitions(document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    //主要看这个方法,把root节点传进去
    doRegisterBeanDefinitions(doc.getdocumentElement());
  }
// 解析完开始准备注册传入root
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);
    if (this.delegate.isDefaultNamespace(root)) {
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
        String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        // We cannot use Profiles.of(...) since profile expressions are not supported
        // in XML config. See SPR-12458 for details.
        if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
          if (logger.isDebugEnabled()) {
            logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                "] not matching: " + getReaderContext().getResource());
          }
          return;
        }
      }
    }
    preProcessXml(root);
    //主要看这个方法,标签具体解析过程
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);
    this.delegate = parent;
  }
// 解析标签
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)) {
            //默认标签解析
            parseDefaultElement(ele, delegate);
          }
          else {
            //自定义标签解析
            delegate.parseCustomElement(ele);
          }
        }
      }
    }
    else {
      delegate.parseCustomElement(root);
    }
  }
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //import标签解析  重要程度 1 ,可看可不看
    if (delegate.nodeNameEquals(ele, import_ELEMENT)) {
      importBeanDefinitionResource(ele);
    }
    //alias标签解析 别名标签  重要程度 1 ,可看可不看
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
    }
    //bean标签,重要程度  5,必须看
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
    }
  }
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //重点看这个方法,重要程度 5 ,解析document,封装成BeanDefinition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
      //该方法功能不重要,设计模式重点看一下,装饰者设计模式,加上SPI设计思想
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
        //完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
        // Register the final decorated instance.
        BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
        getReaderContext().error("Failed to register bean definition with name '" +
            bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
  }

 3.BeanDefinition 是对 Bean 的定义,其保存了 Bean 的各种信息,如属性、构造方法参数、是否单例、是否延迟加载等。这里的注册 Bean 是指将 Bean 定义成 BeanDefinition,之后放入 Spring 容器中,我们常说的容器其实就是 Beanfactory 中的一个 Map,key 是 Bean 的名称,value 是 Bean 对应的 BeanDefinition,这个注册 Bean 的方法由 BeanFactory 子类实现。

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {
    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    //完成BeanDefinition的注册,重点看,重要程度 5
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    //建立别名和 id的映射,这样就可以根据别名获取到id
    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
      for (String alias : aliases) {
        registry.registerAlias(beanName, alias);
      }
    }
  }

4.执行完 registerBeanDefinition 方法后,Bean 的名称和对应的 BeanDefinition 就被放入了容器中,后续获取 Bean 也是从这个容器中获取。 

// BD注册最后的调用
@Override
  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) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
            "Validation of bean definition failed", ex);
      }
    }
    //先判断BeanDefinition是否已经注册
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
        throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
        // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
        if (logger.isInfoEnabled()) {
          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 (logger.isDebugEnabled()) {
          logger.debug("Overriding bean definition for bean '" + beanName +
              "' with a different definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      else {
        if (logger.isTraceEnabled()) {
          logger.trace("Overriding bean definition for bean '" + beanName +
              "' with an equivalent definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
      if (hasBeanCreationStarted()) {
        // Cannot modify startup-time collection elements anymore (for stable iteration)
        synchronized (this.beanDefinitionMap) {
          this.beanDefinitionMap.put(beanName, beanDefinition);
          List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
          updatedDefinitions.addAll(this.beanDefinitionNames);
          updatedDefinitions.add(beanName);
          this.beanDefinitionNames = updatedDefinitions;
          if (this.manualSingletonNames.contains(beanName)) {
            Set updatedSingletons = new linkedHashSet<>(this.manualSingletonNames);
            updatedSingletons.remove(beanName);
            this.manualSingletonNames = updatedSingletons;
          }
        }
      }
      else {
        //把beanDefinition缓存到map中
        // Still in startup registration phase
        this.beanDefinitionMap.put(beanName, beanDefinition);
        //把beanName放到beanDefinitionNames list中,这个list着重记住,bean实例化的时候需要用到
        this.beanDefinitionNames.add(beanName);
        this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
    }
    if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
    }
  }

        最后,我们来做个总结。BeanDefinition 主要是用来描述 Bean,其存储了 Bean 的相关信息,Spring 实例化 Bean 时需读取该 Bean 对应的 BeanDefinition。BeanDefinition 整体可以分为两类,一类是描述通用的 Bean,还有一类是描述注解形式的 Bean。一般前者在 XML 时期定义 标签以及在 Spring 内部使用较多,而现今我们大都使用后者,通过注解形式加载 Bean。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5573609.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存