标准 专业
多元 极客

Spring上古实验室(2)——Spring容器(2)

获取BeanFactory

小调中我们已经大致说了Spring容器初始化的过程,现在我们就来说一说初始化过程中第一个关键核心:获取BeanFactory。
我们来回顾下:

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

首先我们看看AbstractApplicationContext#obtainFreshBeanFactory()方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
     refreshBeanFactory();
     ConfigurableListableBeanFactory beanFactory = getBeanFactory();
     if (logger.isDebugEnabled()) {
          logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
     }
     return beanFactory;
}

搭眼一搂,感觉getBeanFactory()可能是获取BeanFactory的核心方法,呵呵,并不是,我们来看下refreshBeanFactory()中干了些什么:

@Override
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);
     }
}

首先看看有没有BeanFactory,如果有,销毁。接着就重新创建了一个BeanFactory,重置ID,个性化配置,接着就是很关键的加载BeanDefinitions。

首先来看看createBeanFactory()方法:

protected DefaultListableBeanFactory createBeanFactory() {
     return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

挺Easy,就是创建了一个DefaultListableBeanFactory。

接着我们看看customizeBeanFactory()方法:

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
     if (this.allowBeanDefinitionOverriding != null) {
          beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
     }
     if (this.allowCircularReferences != null) {
          beanFactory.setAllowCircularReferences(this.allowCircularReferences);
     }
}

看看允不允许重写啊,可不可以循环依赖啊。

加载BeanDefinition

Follow me,我们即将进入一个核心实现,loadBeanDefinitions():

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
     // 创建一个用于读取BeanFactory信息的读取器。
     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
     // 解析环境
     beanDefinitionReader.setEnvironment(this.getEnvironment());
     // 设置
     beanDefinitionReader.setResourceLoader(this);
     // 使用SAX进行解析
     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
     // 实例化读取器,具体实现为是否需要XML校验,默认需要
     initBeanDefinitionReader(beanDefinitionReader);
     // 解析开始,其实还是前奏
     loadBeanDefinitions(beanDefinitionReader);
}

方法注释基本上已经写得很明确了,我们继续Follow关键点,AbstractXmlApplicationContext#loadBeanDefinitions():

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

很尴尬,正如我所说,依然是前奏,获取相应的配置文件或者配置文件地址。如果能获取到Resource,那么就用这个Resource,如果没有那么就获取Resource的地址。这两个其实都是殊途同归,随便Follow一个:

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

加载Resource

还是传递,继续看AbstractBeanDefinitionReader#loadBeanDefinitions():

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
     // 获取Resource加载器
     ResourceLoader resourceLoader = getResourceLoader();
     if (resourceLoader == null) {
          throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
     }
     // 看看加载器是什么类型
     // 如果是通配符类型,那么可能会匹配多个Resource文件
     if (resourceLoader instanceof ResourcePatternResolver) {
          // Resource pattern matching available.
          try {
               Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
               // 关键点,加载BeanDefinitions
               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;
          }
          ...
     }
     else {
          // 如果不是通配符类型的,就只能加载一个Resource
          Resource resource = resourceLoader.getResource(location);
          // 加载BeanDefinitions
          int loadCount = loadBeanDefinitions(resource);
          if (actualResources != null) {
               actualResources.add(resource);
          }
          if (logger.isDebugEnabled()) {
               logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
          }
          return loadCount;
     }
}

其实到这发现Spring每个接口或者方法设计的时候,基本符合单一职责的原则,一个方法只做一件事情,然后继续传递,那么我们就继续看下XmlBeanDefinitionReader#loadBeanDefinitions()方法:

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

莫慌,只是用装饰器模式设置下编码和字符集,接着,我们走进XmlBeanDefinitionReader#loadBeanDefinitions()方法:

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());
     }
     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 {
               // 将Resource转换成Sax可读的资源文件类型
               InputSource inputSource = new InputSource(inputStream);
               if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
               }
               // 字面翻译,执行加载BeanDefinitions,因为走到这了,谁也不知道下一步是不是真正的加载
               return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
          }
          ...
     }
     ...     
}

使用SAX装载后,我们来到了下一个看似关键的调用,Follow XmlBeanDefinitionReader#doLoadBeanDefinitions():

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
               throws BeanDefinitionStoreException {
     try {
          Document doc = doLoadDocument(inputSource, resource);
          return registerBeanDefinitions(doc, resource);
     }
    ...
    // N个异常处理,为了看起来美观,暂时不列出了,但是咱们实际编码中,还是要严谨
}

把资源文件转换成Document,XmlBeanDefinitionReader#doLoadDocument():

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
     return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
               getValidationModeForResource(resource), isNamespaceAware());
}

DefaultDocumentLoader#loadDocument():

@Override
     public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
     // 配置工厂
     DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
     if (logger.isDebugEnabled()) {
          logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
     }
     // 创建DocumentBuilder
     DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
     // 解析Resource
     return builder.parse(inputSource);
}
  • inputSource:资源文件。
  • entityResolver:元素解析器,如果已经声明,则满足开发者需求。如果没有声明,那么会指定一个默认的。
  • errorHandler:错误处理。
  • validationMode:Xml校验方式,看看使用DTD还是用XSD。如果没有在root元素之前找到任何关于XML文件的声明,那么就用XSD方式进行校验。
  • namespaceAware:是否需要命名空间。
    parse调用的是JDK源码,也就说对Resource文件进行了XML解析。其实也就是没什么看头了,接下来我们回到门口,复习一下:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
               throws BeanDefinitionStoreException {
     try {
          Document doc = doLoadDocument(inputSource, resource);
          return registerBeanDefinitions(doc, resource);
     }
    ...
    // N个异常处理,为了看起来美观,暂时不列出了,但是咱们实际编码中,还是要严谨
}

注册BeanDefinition

既然将XML文件转换成了Document,那么接下来猜一下就知道,需要对XML文件元素进行处理了,这部分称为注册,调用的是XmlBeanDefinitionReader#registerBeanDefinitions():

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
     BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
     int countBefore = getRegistry().getBeanDefinitionCount();
     documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
     return getRegistry().getBeanDefinitionCount() - countBefore;
}

通过代码,我们看到Spring创建并使用一个Document读取器进行注册BeanDefinitions,继续走进DefaultBeanDefinitionDocumentReader#registerBeanDefinitions():

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
     this.readerContext = readerContext;
     logger.debug("Loading bean definitions");
     Element root = doc.getDocumentElement();
     doRegisterBeanDefinitions(root);
}

咦,这里好像要变成了Dom解析了,获取根元素,执行DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions()方法:

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);
               if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isInfoEnabled()) {
                         logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                   "] not matching: " + getReaderContext().getResource());
                    }
                    return;
               }
          }
     }
     // 默认空执行,开发者可以进行个性化
     preProcessXml(root);
     // 解析Bean标签
     parseBeanDefinitions(root, this.delegate);
     // 默认空执行,开发者可以进行个性化
     postProcessXml(root);
     this.delegate = parent;
}

组装BeanDefinition

我们来继续看一下DefaultBeanDefinitionDocumentReader#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)) {                                    
                         parseDefaultElement(ele, delegate);                                    
                    }                                                                          
                    else {                                                                     
                         delegate.parseCustomElement(ele);                                      
                    }                                                                          
               }                                                                              
          }                                                                                  
     }                                                                                      
     else {                                                                                 
          delegate.parseCustomElement(root);                                                 
     }                                                                                      
}                                                                                                                                                

可以看出,Spring采用循环的方式,遍历每一个需要解析的节点,节点元素又分为两类,默认元素和自定义元素,我们看一下默认元素的解析方法:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
     if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {                               
          importBeanDefinitionResource(ele);                                            
     }                                                                                 
     else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {                           
          processAliasRegistration(ele);                                                
     }                                                                                 
     else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {                            
          processBeanDefinition(ele, delegate);                                         
     }                                                                                 
     else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {                    
          // recurse                                                                    
          doRegisterBeanDefinitions(ele);                                               
     }                                                                                 
}                                                                                     

这里其实就展现了ApplicationContext规定的四大默认标签,import、alias、bean、beans。我们首先来看一下DefaultBeanDefinitionDocumentReader#processBeanDefinition()方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {                
     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);                             
     if (bdHolder != null) {                                                                               
          bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);                              
          try {                                                                                             
               // 注册BeanDefinition                              
               BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
          }                                                                                                 
          catch (BeanDefinitionStoreException ex) {                                                         
               getReaderContext().error("Failed to register bean definition with name '" +                   
                         bdHolder.getBeanName() + "'", ele, ex);                                               
          }                                                                                                 
          // 告知监听器,这个BeanDefinition已经注册完毕                                                           
          getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));                
     }                                                                                                     
}                                                                                                         

标签解析

预告一下,这里其实是将解析后的BeanDefinitions和BeanName、Alias合并为了BeanDefinitionHolder,然后使用BeanDefinitionReaderUtils#registerBeanDefinition()来注册BeanDefinitions。

我们先看看BeanDefinitionParserDelegate#parseBeanDefinitionElement()方法创建BeanDefinitionHolder的过程:

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

继续看BeanDefinitionParserDelegate#parseBeanDefinitionElement()方法:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
     // 获取ID
     String id = ele.getAttribute(ID_ATTRIBUTE);
     // 获取Name
     String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
     // 获取Aliases
     List<String> aliases = new ArrayList<>();
     if (StringUtils.hasLength(nameAttr)) {
          String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
          aliases.addAll(Arrays.asList(nameArr));
     }
     // 找一个合适位置,让beanName不为空
     String beanName = id;
     if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
          beanName = aliases.remove(0);
          if (logger.isDebugEnabled()) {
               logger.debug("No XML 'id' specified - using '" + beanName +
                         "' as bean name and " + aliases + " as aliases");
          }
     }
     // 检查下这个名字的唯一性
     if (containingBean == null) {
          checkNameUniqueness(beanName, aliases, ele);
     }
     // 将元素解析为BeanDefinition
     AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
     if (beanDefinition != null) {
          if (!StringUtils.hasText(beanName)) {
               try {
                    if (containingBean != null) {
                         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 (logger.isDebugEnabled()) {
                         logger.debug("Neither XML 'id' nor 'name' specified - " +
                                   "using generated bean name [" + beanName + "]");
                    }
               }
               ...
          }
          String[] aliasesArray = StringUtils.toStringArray(aliases);
          // 封装成BeanDefinitionHolder并返回
          return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
     }
     return null;
}

这里的核心关键点是解析元素并转换为BeanDefinition,我们看下BeanDefinitionParserDelegate#parseBeanDefinitionElement()方法:

public AbstractBeanDefinition parseBeanDefinitionElement(
          Element ele, String beanName, BeanDefinition containingBean) {
     this.parseState.push(new BeanEntry(beanName));
     String className = null;
     if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
          className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
     }
     try {
          String parent = null;
          if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
               parent = ele.getAttribute(PARENT_ATTRIBUTE);
          }
          // 创建BeanDefinitions
          AbstractBeanDefinition bd = createBeanDefinition(className, parent);
          // 解析属性
          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
          //
          parseMetaElements(ele, bd);
          // 自定义配置,覆盖或者替换方法
          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
          // 解析构造器元素
          parseConstructorArgElements(ele, bd);
          // 解析property标签
          parsePropertyElements(ele, bd);
          // 解析qualifier标签
          parseQualifierElements(ele, bd);
          bd.setResource(this.readerContext.getResource());
          bd.setSource(extractSource(ele));
          return bd;
     }
     return null;
}

我们来看下BeanDefinitionParserDelegate#createBeanDefinition

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
          throws ClassNotFoundException {
     return BeanDefinitionReaderUtils.createBeanDefinition(
               parentName, className, this.readerContext.getBeanClassLoader());
}

继续进入到BeanDefinitionReaderUtils#createBeanDefinition方法:

public static AbstractBeanDefinition createBeanDefinition(
          String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
     GenericBeanDefinition bd = new GenericBeanDefinition();
     bd.setParentName(parentName);
     if (className != null) {
          if (classLoader != null) {
               bd.setBeanClass(ClassUtils.forName(className, classLoader));
          }
          else {
               bd.setBeanClassName(className);
          }
     }
     return bd;
}

这样,一个BeanDefinition就创建了。

我们继续回到parseBeanDefinitionElement()方法, 标签解析无外乎使用循环遍历节点,获取相应的元素属性并添加到BeanDefinition,这里笔者举一个例子,大家可以发散思维:

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
     NodeList nl = beanEle.getChildNodes();
     for (int i = 0; i < nl.getLength(); i++) {
          Node node = nl.item(i);
          if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
               parsePropertyElement((Element) node, bd);
          }
     }
}

这样,BeanDefinition的解析也结束了。
我们总结一下,BeanDefinition解析的过程:

  1. 首先根据className创建一个GenericBeanDefinition类型的BeanDefinition。
  2. 将Bean的属性键值添加到BeanDefinition中。
  3. 添加描述。
  4. 将是否有获取器注入和替换注入添加到BeanDefinition中。
  5. 解析bean标签中形如constructor、property、qualifier等标签,值塞入BeanDefinition中。
  6. BeanDefinition解析完成。
    解析完BeanDefinitions后,被BeanDefinitionHolder包装后,就需要注册到缓存中,我们复习一下之前的代码:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {                
     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);                             
     if (bdHolder != null) {                                                                               
          bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);                              
          try {                                                                                             
               // 注册BeanDefinition到注册表中                                           
               BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
          }                                                                                                 
          ...                                                                                  
          // 告知监听器,这个BeanDefinition已经注册完毕                                                       
          getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));                
     }                                                                                                     
}                                                                                                         

一步一步来,我们进入BeanDefinitionReaderUtils#registerBeanDefinition()中:

public static void registerBeanDefinition(
          BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
          throws BeanDefinitionStoreException {
     // 获取注册ID
     String beanName = definitionHolder.getBeanName();
     registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
     // 如果有alias,同时需要注册alias
     String[] aliases = definitionHolder.getAliases();
     if (aliases != null) {
          for (String alias : aliases) {
               registry.registerAlias(beanName, alias);
          }
     }
}

这里分为根据beanName注册alias注册,用于满足不同的注入场景,首先我们看一下DefaultListableBeanFactory的beanName注册:

@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");
     // 如果是原始AbstractBeanDefinition类型,那么需要对beanDefinition进行校验
     if (beanDefinition instanceof AbstractBeanDefinition) {
          try {
               ((AbstractBeanDefinition) beanDefinition).validate();
          }
          ...
     }
     BeanDefinition oldBeanDefinition;
     // 看看是否已经加载过这个beanDefintion
     oldBeanDefinition = this.beanDefinitionMap.get(beanName);
     if (oldBeanDefinition != null) {
          // 不允许覆盖
          if (!isAllowBeanDefinitionOverriding()) {
               throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                         "': There is already [" + oldBeanDefinition + "] bound.");
          }
          // 权重有问题
          else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
               // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
               if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                              "' with a framework-generated bean definition: replacing [" +
                              oldBeanDefinition + "] with [" + beanDefinition + "]");
               }
          }
          // 当前的BeanDefinition和原有的BeanDefinition不相同
          else if (!beanDefinition.equals(oldBeanDefinition)) {
               if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                              "' with a different definition: replacing [" + oldBeanDefinition +
                              "] with [" + beanDefinition + "]");
               }
          }
          else {
               // 如果开了debug日志级别
               if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                              "' with an equivalent definition: replacing [" + oldBeanDefinition +
                              "] with [" + beanDefinition + "]");
               }
          }
          // 没啥问题就覆盖了
          this.beanDefinitionMap.put(beanName, beanDefinition);
     }
     // 如果BeanDefinition没有被加载过
     else {
          // BeanDefinition正在创建过程中
          if (hasBeanCreationStarted()) {
               // 锁住
               synchronized (this.beanDefinitionMap) {
                    // 注册
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    // 如果处于单例模式创建中,移除
                    if (this.manualSingletonNames.contains(beanName)) {
                         Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                         updatedSingletons.remove(beanName);
                         this.manualSingletonNames = updatedSingletons;
                    }
               }
          }
          else {
               // 如果没有处于创建中,那么直接添加
               this.beanDefinitionMap.put(beanName, beanDefinition);
               this.beanDefinitionNames.add(beanName);
               this.manualSingletonNames.remove(beanName);
          }
          this.frozenBeanDefinitionNames = null;
     }
     if (oldBeanDefinition != null || containsSingleton(beanName)) {
          // 重置所有beanName对应的缓存
          resetBeanDefinition(beanName);
     }
}

看似挺复杂,其实很好理解,和我们平时写一段复杂逻辑差不多,其实这段也可以理解为一段简单需求的多种情况考虑。

  1. 首先对AbstractBeanDefinition类型的bean进行校验,主要是对MethodOverride进行校验。
  2. 如果已经加载过这个BeanDefinition,那么就对这个BeanDefinition进行一系列的校验,如果没有问题,就会覆盖原有的BeanDefinition。
  3. 如果beanDefinitionMap中没有这个BeanDefinition,那么会有两种情况。第一种情况是如果这个BeanDefinition处于创建过程中,那么就锁住beanDefinitionMap并使用CopyOnWrite机制注册BeanDefinition。第二种情况是完全不存在的,那么我们就直接进行注册。
  4. 如果是单例bean或者是已经存在BeanDefinition,那么会重置BeanDefinition的缓存。
    接下来我们回过头看一下alias标签的注册,首先复习下代码:
public static void registerBeanDefinition(
          BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
          throws BeanDefinitionStoreException {
     ...
     // 如果有alias,同时需要注册alias
     String[] aliases = definitionHolder.getAliases();
     if (aliases != null) {
          for (String alias : aliases) {
               registry.registerAlias(beanName, alias);
          }
     }
}

接着我们继续看BeanDefinitionReaderUtils#registerAlias()方法,这里会有两个选择,我们选择GernericApplicationContext的实现:

@Override
public void registerAlias(String beanName, String alias) {
     this.beanFactory.registerAlias(beanName, alias);
}

继续走,来到了SimpleAliasRegistry#registerAlias()方法,殊途同归:

@Override
public void registerAlias(String name, String alias) {
     Assert.hasText(name, "'name' must not be empty");
     Assert.hasText(alias, "'alias' must not be empty");
     if (alias.equals(name)) {
          this.aliasMap.remove(alias);
     }
     else {
          String registeredName = this.aliasMap.get(alias);
          if (registeredName != null) {
               if (registeredName.equals(name)) {
                    // 已经注册了,不需要重新注册
                    return;
               }
               if (!allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                              name + "': It is already registered for name '" + registeredName + "'.");
               }
          }
          // 看看有没有alias循环依赖的问题
          checkForAliasCircle(name, alias);
          this.aliasMap.put(alias, name);
     }
}

首先,我们会看看alias和beanName是否相同,如果相同,则去掉alias标记。
接着,如果aliasMap中如果有alias对应的beanName,那么如果名字重复,不重新注册。
最后,如果没有以上问题,那么先检查下有没有循环依赖的问题,然后将注册alias。
alias注册完毕后,接下来就是告知监听器这个BeanDefinition已经注册完毕了,你们可以进场了,我们首先复习一下注入监听器的策略:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {                
     ...                                                        
     getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));                
     }                                                                                                     
}                                                                                                         

获取ReaderContext实现,并调用ReaderContext#fireComponentRegistered()方法:

public void fireComponentRegistered(ComponentDefinition componentDefinition) {
     this.eventListener.componentRegistered(componentDefinition);
}

向EventListener注入ComponentDefinition,调用的是EmptyReaderEventListener#componentRegistered()方法:

@Override
public void componentRegistered(ComponentDefinition componentDefinition) {
     // no-op
}

空实现!其实这就是告诉我们,具体的监听策略是需要我们自己来实现。
我们回顾一下processBeanDefinition做了些什么:

  1. 解析Bean标签的元素,并封装进BeanDefinition中,然后使用BeanDefinitionHolder继续包装一层。
  2. 将BeanDefinitionHolder交给注册器进行BeanDefinition注册。
  3. 注册完毕,告知监听器可以开始监听BeanDefinition了,具体监听逻辑需要自己实现。

总结

其实到这里,bean标签的解析就结束了,是不是都已经忘了怎么来的了,没关系,我们复盘一下:

  1. 首先调用AbstractApplicationContext#refresh()进行容器初始化。
  2. refresh()方法中首先进行容器初始化的预处理。
  3. 调用AbstractApplicationContext#obtainFreshBeanFactory()进行创建BeanFactory。
  4. 调用AbstractRefreshableApplicationContext#refreshBeanFactory()加载BeanDefinition。
  5. 接下来就是根据Resource文件进行标签解析,封装BeanDefinition,注册BeanDefinition等关键操作。
  6. BeanFactory创建完成。
赞(0) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫