Spring5源码4-XML配置文件解析

欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

1. spring项目搭建

1.1 导入jar依赖

spring中最核心的4个jar:

  • spring-beans
  • spring-core
  • spring-context
  • spring-expression

一个最最简单的spring工程,理论上就只需要一个jar就够了

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
</dependency>
复制代码

1.2 XSD引入

spring中要引入自定义标签,必须要引入其对应的XSD文件,XSD 是编写 xml 文件的一种规范,有了这个规范才能校验 xml 是否写错;

例如要引入自定义标签<context:component-scan base-package="org.example"/>,就必须引入这个标签对应的 XSD 文件。

image.png

在标签对应的jar包下面找到对应的spring.schemas,在这个文件中就会有对应的XSD路径和命名空间。

image.png

1.3 spring 容器加载方式

1. 类路径获取配置文件

ApplicationContext applicationContext= new ClassPathXmlApplicationContext("beans.xml");
复制代码

2、文件系统路径获取配置文件【绝对路径】

ApplicationContext applicationContext = new FileSystemXmlApplicationContext("E:\\idea\\public\\springdemo\\src\\main\\resources\\spring.xml");
复制代码

3、无配置文件加载容器

ApplicationContext applicationContext = new AnnotationConfigApplicationContext("MainText.class");
复制代码

4、springboot加载容器

ApplicationContext applicationContext = new EmbeddedWebApplicationContext();
复制代码

2. xml配置文件案例

AbstractApplicationContext.refresh()方法,是spring容器启动过程中的核心方法,spring容器要加载必须执行该方法。

2.1 测试类

@Component
public class Person {

   private String name;

// @Autowired  依赖的组件是多实例的时候不能使用@Autowired
   private Cat cat;

   @Lookup // 去容器中找,@Bean的这种方式注册的Person @Lookup不生效
   public Cat getCat() {
      return cat;
   }

   public void setCat(Cat cat) {
      this.cat = cat;
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }

   @Override
   public String toString() {
      return "Person{" +
            "name='" + name + ''' +
            '}';
   }
复制代码

容器加载

public class XmlMainText {

   public static void main(String[] args) {
      ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("beans.xml");

      Person bean = context.getBean(Person.class);
      System.out.println(bean);

   }
}
复制代码

spring.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"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      https://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="com.hsf.spring"></context:component-scan>

   <bean  class="com.hsf.spring.beans.Person" id="person">
      <property name= "name" value="zhangsan"></property>
   </bean>
</beans>
复制代码

打印结果

zhangsan
复制代码

3. xml配置文件解析源码

ClassPathXmlApplicationContext构造器:

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[] {configLocation}, true, null);
}
复制代码

进入this

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {

   super(parent);
   // 创建解析器,设置configLocations
   setConfigLocations(configLocations);
   if (refresh) {
      // 刷新容器
      refresh();
   }
}
复制代码
  • setConfigLocations(configLocations);----创建解析器,设置configLocations

image.png

3.1 核心方法AbstractApplicationContext#refresh()

// 容器刷新的十二大步骤
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 容器启动的状态
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

      // Prepare this context for refreshing.
      // 1.准备上下文环境
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      /** 1、创建BeanFactory对象
      *  2、xml解析
      *  传统标签解析:bean、import等
      *  自定义标签解析 如:<context:component-scan base-package="org.example"/>
      *  自定义标签解析流程:
      *     a、根据当前解析标签的头信息找到对应的namespaceUri
      *     b、加载spring所以jar中的spring.handlers文件。并建立映射关系
      *     c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
      *     d、调用类的init方法,init方法是注册了各种自定义标签的解析类
      *     e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
      * 3、把解析出来的xml标签封装成BeanDefinition对象
      */
      // 2. 工厂创建:BeanFactory 第一次开始创建的时候,有xml解析逻辑
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      // 3. 预准备工厂,给容器中注册了环境信息作为单实例Bean  方便后续自动装配
      // 并且放了一些后置处理器(监听、xxxAware功能)
      prepareBeanFactory(beanFactory);

      try {
         //  Allows post-processing of the bean factory in context subclasses.
         // 留给子类的模板方法,允许子类继续对工厂执行一些处理
         postProcessBeanFactory(beanFactory);

         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         // Invoke factory processors registered as beans in the context.
         // 5. 【大核心】工厂增强:执行所有的BeanFactory 后置增强器 利用BeanFactory后置增强器对工厂进行修改或增强
         // 配置类也会在这个解析
         // BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor 完成对这两个接口的调用
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         // 6. 【核心】注册 所有的Bean的后置处理器
         registerBeanPostProcessors(beanFactory);
         beanPostProcess.end();

         // Initialize message source for this context.
         // 7. 初始化国际化组件
         initMessageSource();

         // Initialize event multicaster for this context.
         // 8. 初始化事件派发 功能
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         // 9. 留给子类继续增强处理逻辑
         // 这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的
         onRefresh();

         // Check for listener beans and register them.
         // 10. 注册事件监听器,从容器中获取所有的ApplicationListener
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         // 11. 【大核心】bean创建:完成BeanFactory 初始化(工厂里面所有的组件都好了)
         /*
          * 这个方法一定要理解要具体看
          * 1、bean实例化过程
          * 2、ioc
          * 3、注解支持
          * 4、BeanPostProcessor的执行
          * 5、Aop的入口
          */
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         // 12. 发布事件
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
         contextRefresh.end();
      }
   }
}
复制代码

本文 重点分析obtainFreshBeanFactory()方法中关于 xml配置文件解析相关,其他步骤以后再说。

3.2 obtainFreshBeanFactory()

该方法主要进行xml解析工作,流程如下:

  1. 创建XmlBeanDefinitionReader对象
  2. 通过Reader对象加载配置文件
  3. 根据加载的配置文件把配置文件封装成document对象
  4. 创建BeanDefinitionDocumentReader对象,DocumentReader负责对document对象解析
  5. parseDefaultElement(ele, delegate);负责常规标签解析
  6. delegate.parseCustomElement(ele);负责自定义标签解析
  7. 最终解析的标签封装成BeanDefinition并缓存到容器中

进入obtainFreshBeanFactory()

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   // 刷新BeanFactory,注解模式下就是准备工厂,xml模式下会解析xml
   refreshBeanFactory();
   return getBeanFactory();
}
复制代码

进入refreshBeanFactory(); 这里spring使用了模板设计模式,通过子类实现钩子方法来干预父类的业务执行流程。 image.png

3.3 AbstractRefreshableApplicationContext#refreshBeanFactory()

protected final void refreshBeanFactory() throws BeansException {

    //如果BeanFactory不为空,则清除BeanFactory和里面的实例
    if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
    }
    try {
            // 1.创建DefaultListableBeanFactory
            //BeanFactory 实例工厂
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());

            // 2.设置是否可以循环依赖 allowCircularReferences
            //是否允许使用相同名称重新注册不同的bean实现.
            customizeBeanFactory(beanFactory);

            // 3.解析xml,并把xml中的标签封装成BeanDefinition对象
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory;
            }
    }
    catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}
复制代码

3.3.1 AbstractXmlApplicationContext#loadBeanDefinitions(beanFactory);

创建XmlBeanDefinitionReader对象

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   // 准备一个BeanDefinitionReader  读取器, 这里是一个委托模式
   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);

   // todo 加载所有BeanDefinition
   loadBeanDefinitions(beanDefinitionReader);
}
复制代码

3.3.2 AbstractXmlApplicationContext#loadBeanDefinitions(beanDefinitionReader);

  • 后面会多次调用好几个类中的loadBeanDefinitions这个方法
  • 通过Reader对象加载配置文件
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   // 获取所有的配置文件的位置信息,可以一次传入很多配置文件
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      // todo 读取文件
      reader.loadBeanDefinitions(configLocations);
   }
}
复制代码

3.3.3 AbstractBeanDefinitionReader#loadBeanDefinitions(configLocations);

@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;
}
复制代码

3.3.4 AbstractBeanDefinitionReader#loadBeanDefinitions(location);

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

3.3.5 AbstractBeanDefinitionReader#loadBeanDefinitions(location, null);

用流的方式加载配置文件,然后封装成Resource对象

public int loadBeanDefinitions(String location, @Nullable Set<Resource> 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);
         // todo 加载
         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;
   }
}
复制代码

3.3.6 AbstractBeanDefinitionReader#loadBeanDefinitions(resources);

@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int count = 0;
   for (Resource resource : resources) {
      // todo
      count += loadBeanDefinitions(resource);
   }
   return count;
}
复制代码

loadBeanDefinitions(resource)是模板设计模式,钩子方法

3.3.7 XmlBeanDefinitionReader#loadBeanDefinitions(new EncodedResource(resource))

EncodedResource带编码的对Resource对象的封装

@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   // EncodedResource 带编码的对Resource对象的封装
   return loadBeanDefinitions(new EncodedResource(resource));
}
复制代码

3.3.8 XmlBeanDefinitionReader#doLoadBeanDefinitions(inputSource, encodedResource.getResource())

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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

   if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }

   // 获取Resource对象中的xml文件流对象
   try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
      //InputSource是jdk中的sax xml文件解析对象
      InputSource inputSource = new InputSource(inputStream);
      if (encodedResource.getEncoding() != null) {
         inputSource.setEncoding(encodedResource.getEncoding());
      }
      // todo
      return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
   }
复制代码

3.3.9 XmlBeanDefinitionReader#doLoadDocument(inputSource, resource)

根据加载的配置文件把配置文件封装成document对象

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {

   try {
      // 把inputSource 封装成Document文件对象,这是jdk的API
      // dom解析工具 把xml变成Document
      Document doc = doLoadDocument(inputSource, resource);
      // todo 主要看这个方法,根据解析出来的document对象,拿到里面的标签元素封装成BeanDefinition
      int count = registerBeanDefinitions(doc, resource);
      if (logger.isDebugEnabled()) {
         logger.debug("Loaded " + count + " bean definitions from " + resource);
      }
      return count;
   }
   ...
}
复制代码

3.3.10 XmlBeanDefinitionReader#registerBeanDefinitions(doc, resource)

这个document对象就是配置文件bean.xml里的内容

image.png

创建BeanDefinitionDocumentReader对象,DocumentReader负责对document对象解析

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

   //委托模式,BeanDefinitionDocumentReader委托这个类进行document的解析
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   //主要看这个方法,createReaderContext(resource) XmlReaderContext上下文,封装了XmlBeanDefinitionReader对象
   // todo BeanDefinitionDocumentReader 把Document解析
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}
复制代码

3.3.11 DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

把root节点传进去

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   doRegisterBeanDefinitions(doc.getDocumentElement());
}
复制代码

3.3.12 DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element root)

image.png

3.3.13 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

  • parseDefaultElement(ele, delegate);负责默认标签解析
  • delegate.parseCustomElement(ele);负责自定义标签解析
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;

            // 遍历文档中的所有标签
            //判断是否是默认的Namespace,http://www.springframework.org/schema/beans
            if (delegate.isDefaultNamespace(ele)) {
               // bean标签,走默认标签解析
               parseDefaultElement(ele, delegate);
            }
            else {
               // 自定义标签解析
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}
复制代码

默认标签解析( < bean >)

  • 解析document对象并包装成BeanDefinition对象
  • 解析bean标签内的属性(id,class,scope,primary),并设置到BeanDefinition对象中
  • 再解析bean下面的子标签(lookup-method,replaced-method,property,constructor-arg等)
  • 把BeanDefinition封装成BeanDefinitionHolder对象
  • 对BeanDefinitionHolder对象进行缓存和注册

3.3.13.1 DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

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);
    }
}
复制代码

3.3.13.2 DefaultBeanDefinitionDocumentReader#processBeanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

   // todo 把当前标签解析完了,BeanDefinition 和beanName都封装了Holder中
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      // 装饰者设计模式,加上SPI设计思想,解析namespaceuri方法
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         // todo 完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
         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.3.13.3 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   //获取bean标签内的id
   String id = ele.getAttribute(ID_ATTRIBUTE);
   //获取bean标签内的name
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

   //获取bean标签内的别名
   List<String> aliases = new ArrayList<>();
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }

   //将id赋给beanName
   String beanName = id;
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isTraceEnabled()) {
         logger.trace("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   //检查beanName是否重复
   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }

   // todo 解析bean,返回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);
               // Register an alias for the plain bean class name, if still possible,
               // if the generator returned the class name plus a suffix.
               // This is expected for Spring 1.2/2.0 backwards compatibility.
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  aliases.add(beanClassName);
               }
            }
            if (logger.isTraceEnabled()) {
               logger.trace("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      // 将beanDefinition封装成BeanDefinitionHolder返回
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}
复制代码

3.3.13.4 BeanDefinitionParserDelegate#parseBeanDefinitionElement(ele, beanName, containingBean)

解析bean标签,包装成beanDefinition对象返回

public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {

   this.parseState.push(new BeanEntry(beanName));

   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
   String parent = null;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {

      //创建GenericBeanDefinition对象
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
      // 以下是解析Bean标签里面的数据,填充完BeanDefinition

      // 解析bean标签的属性,并把解析出来的属性设置到BeanDefinition对象中
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

      //解析bean中的meta标签
      parseMetaElements(ele, bd);
      //解析bean中的lookup-method标签  重要程度:2
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      //解析bean中的replaced-method标签  重要程度:2
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

      //解析bean中的constructor-arg标签  重要程度:2
      parseConstructorArgElements(ele, bd);
      //解析bean中的property标签  重要程度:2
      parsePropertyElements(ele, bd);
      parseQualifierElements(ele, bd);

      bd.setResource(this.readerContext.getResource());
      bd.setSource(extractSource(ele));

      //包装成beanDefinition对象返回
      return bd;
   }
   catch (ClassNotFoundException ex) {
      error("Bean class [" + className + "] not found", ele, ex);
   }
   catch (NoClassDefFoundError err) {
      error("Class that bean class [" + className + "] depends on not found", ele, err);
   }
   catch (Throwable ex) {
      error("Unexpected failure during bean definition parsing", ele, ex);
   }
   finally {
      this.parseState.pop();
   }

   return null;
}
复制代码

3.3.13.5 回到3.3.13.3步,将beanDefinition封装成BeanDefinitionHolder返回

image.png

BeanDefinitionHolder 构造器:

public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, @Nullable String[] aliases) {
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");
   Assert.notNull(beanName, "Bean name must not be null");
   this.beanDefinition = beanDefinition;
   this.beanName = beanName;
   this.aliases = aliases;
}
复制代码

3.3.13.6 回到3.3.13.2步,BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
   return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
复制代码
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
      Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

   BeanDefinitionHolder finalDefinition = originalDef;

   //根据bean标签属性装饰BeanDefinitionHolder,比如<bean class="xx" p:username="fisher"/>
   // Decorate based on custom attributes first.
   NamedNodeMap attributes = ele.getAttributes();
   for (int i = 0; i < attributes.getLength(); i++) {
      Node node = attributes.item(i);
      finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
   }

   // Decorate based on custom nested elements.
   // 根据bean标签子元素装饰BeanDefinitionHolder
   NodeList children = ele.getChildNodes();
   for (int i = 0; i < children.getLength(); i++) {
      Node node = children.item(i);
      if (node.getNodeType() == Node.ELEMENT_NODE) {
         // todo
         finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
      }
   }
   return finalDefinition;
}
复制代码

3.3.13.7 BeanDefinitionParserDelegate#decorateIfRequired(Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd)

public BeanDefinitionHolder decorateIfRequired(
      Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

   // 根据node获取到node的命名空间,形如:http://www.springframework.org/schema/p
   String namespaceUri = getNamespaceURI(node);
   if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
      // todo 这里有SPI服务发现的思想,根据配置文件获取namespaceUri对应的处理类
      NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
      if (handler != null) {
         //调用NamespaceHandler处理类的decorate方法,开始具体装饰过程,并返回装饰完的对象
         //org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
         BeanDefinitionHolder decorated =
               handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
         if (decorated != null) {
            return decorated;
         }
      }
      else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
      }
      else {
         // A custom namespace, not to be handled by Spring - maybe "xml:...".
         if (logger.isDebugEnabled()) {
            logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
         }
      }
   }
   return originalDef;
}
复制代码

3.3.13.8 DefaultNamespaceHandlerResolver#resolve(String namespaceUri)

@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
   // todo 获取spring中所有jar包里面的 "META-INF/spring.handlers"文件,并且建立uri和处理类的映射关系
   Map<String, Object> handlerMappings = getHandlerMappings();
   //根据namespaceUri:http://www.springframework.org/schema/p,获取到这个命名空间的处理类
   // todo 通过uri在映射关系内找到处理类
   Object handlerOrClassName = handlerMappings.get(namespaceUri);
   if (handlerOrClassName == null) {
      return null;
   }
   else if (handlerOrClassName instanceof NamespaceHandler) {
      return (NamespaceHandler) handlerOrClassName;
   }
   else {
      String className = (String) handlerOrClassName;
      try {
         Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
         if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
            throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                  "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
         }
         // todo 通过类名反射出处理类
         NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
         //调用处理类的init方法,在init方法中完成标签元素解析类的注册
         namespaceHandler.init();
         handlerMappings.put(namespaceUri, namespaceHandler);
         return namespaceHandler;
      }
      catch (ClassNotFoundException ex) {
         throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
               "] for namespace [" + namespaceUri + "]", ex);
      }
      catch (LinkageError err) {
         throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
               className + "] for namespace [" + namespaceUri + "]", err);
      }
   }
}
复制代码

3.3.13.9 DefaultNamespaceHandlerResolver#getHandlerMappings()

private Map<String, Object> getHandlerMappings() {
   Map<String, Object> handlerMappings = this.handlerMappings;
   if (handlerMappings == null) {
      synchronized (this) {
         handlerMappings = this.handlerMappings;
         if (handlerMappings == null) {
            if (logger.isTraceEnabled()) {
               logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
            }
            try {
               // 用InputStream流的方式,加载"META-INF/spring.handlers"文件,包装成Properties 对象
               // handlerMappingsLocation 为常量META-INF/spring.handlers
               Properties mappings =
                     PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
               if (logger.isTraceEnabled()) {
                  logger.trace("Loaded NamespaceHandler mappings: " + mappings);
               }
               //所有"META-INF/spring.handlers"文件里面的内容建立映射关系
               handlerMappings = new ConcurrentHashMap<>(mappings.size());
               CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
               this.handlerMappings = handlerMappings;
            }
            catch (IOException ex) {
               throw new IllegalStateException(
                     "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
            }
         }
      }
   }
   return handlerMappings;
}
复制代码
  • DefaultNamespaceHandlerResolver类中定义了一个常量,文件路径META-INF/spring.handlers
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
复制代码
  • 构造方法,点击this
public DefaultNamespaceHandlerResolver() {
   this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
复制代码
  • 赋值操作
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader, String handlerMappingsLocation) {
   Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
   this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
   this.handlerMappingsLocation = handlerMappingsLocation;
}
复制代码

3.3.13.10 回到3.3.13.8步,DefaultNamespaceHandlerResolver#resolve(String namespaceUri)

image.png

image.png

image.png

点开处理类,可以发现所有的处理类都会实现NamespaceHandler接口

public class SimplePropertyNamespaceHandler implements NamespaceHandler {
复制代码

通过反射实例化处理类,并强转为NamespaceHandler

image.png

调用init()方法

image.png

3.3.13.11 回到3.3.13.2 步

DefaultBeanDefinitionDocumentReader#registerBeanDefinition(bdHolder, getReaderContext().getRegistry())

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

   // todo 把当前标签解析完了,BeanDefinition 和beanName都封装了Holder中
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      // 装饰者设计模式,加上SPI设计思想,解析namespaceuri方法
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         // todo 完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
         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));
   }
}
复制代码

完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册:

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   // todo  完成BeanDefinition的注册,重点看,重要程度 5
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   // 建立别名和 id的映射,这样就可以根据别名获取到id
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}
复制代码

image.png

3.3.13.12 DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

完成BeanDefinition的注册

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

   // todo 先判断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 + "]");
         }
      }
      // 把beanDefinition缓存到map中
      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<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            removeManualSingletonName(beanName);
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         //把beanName放到beanDefinitionNames list中,这个list着重记住,bean实例化的时候需要用到
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
   else if (isConfigurationFrozen()) {
      clearByTypeCache();
   }
}
复制代码
  • beanDefinitionMap:beanDefinitionNames存了所有beanDefiniton的名称

3.3.14 DefaultBeanDefinitionDocumentReader#delegate.parseCustomElement(ele)

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;

            // 遍历文档中的所有标签
            //判断是否是默认的Namespace,http://www.springframework.org/schema/beans
            if (delegate.isDefaultNamespace(ele)) {
               // bean标签,走默认标签解析
               parseDefaultElement(ele, delegate);
            }
            else {
               // 自定义标签解析
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}
复制代码

自定义标签解析( < context>)

image.png

3.3.14.1 BeanDefinitionParserDelegate#parseCustomElement(Element ele)

public BeanDefinition parseCustomElement(Element ele) {
   return parseCustomElement(ele, null);
}

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
   String namespaceUri = getNamespaceURI(ele);
   if (namespaceUri == null) {
      return null;
   }
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   // todo
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
复制代码

使用xml的方式加载spring的配置文件,启动spring容器。

image.png

3.3.14.2 BeanDefinitionParserDelegate#parse(Element element, ParserContext parserContext)

image.png

public BeanDefinition parse(Element element, ParserContext parserContext) {
   // todo
   BeanDefinitionParser parser = findParserForElement(element, parserContext);
   // parse 方法
   return (parser != null ? parser.parse(element, parserContext) : null);
}
复制代码

3.3.14.3 BeanDefinitionParserDelegate#findParserForElement(Element element, ParserContext parserContext)

image.png

image.png

init方法建立了映射关系

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

   @Override
   public void init() {
      registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
      registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
      registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
      registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
      registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
   }

}
复制代码

将ComponentScanBeanDefinitionParser放入map中,对应的key是component-scan:

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
   this.parsers.put(elementName, parser);
}
复制代码

parsers是父类的Map,父类NamespaceHandlerSupport实现NamespaceHandler接口,所以handler才能实现多态:

image.png

3.3.14.4 返回parser对象,回到3.3.14.2步,进入ComponentScanBeanDefinitionParser#parse(Element element, ParserContext parserContext)

parser()主要工作:

  • 1、扫描路径.class后缀的文件
  • 2、要判断类上是否有注解,并封装成metadata对象
  • 3、genericBeanDefinition.setBeanClass(BeanClass.class)
  • 4、完成BeanDefinition的注册(beandefinitionNames,beandefinitionMap)

创建注解扫描器

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
   //获取basePackage属性
   String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
   //可以用逗号分开
   basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
   String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

   // todo 创建注解扫描器
   // Actually scan for bean definitions and register them.
   ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
   // todo 扫描并把扫描的类封装成beanDefinition对象  核心方法,重要程度 5
   Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
   // 如果加了@Component的类中,又加了@Autowired、@Value、@Resource、@PostConstruct、@PreDestroy注解,使用这个方法就可以扫描得到
   // 在Bean的实例化过程中有至关重要的作用
   registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

   return null;
}
复制代码

3.3.14.5 ComponentScanBeanDefinitionParser#configureScanner(parserContext, element)

image.png

//使用默认的过滤器
boolean useDefaultFilters = true;
if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
	useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
}

//创建注解的扫描器
// Delegate bean definition registration to scanner class.
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
复制代码

image.png

3.3.14.6 ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner()构造方法

使用默认的过滤器

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
      Environment environment, @Nullable ResourceLoader resourceLoader) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   this.registry = registry;

   // todo
   if (useDefaultFilters) {
      registerDefaultFilters();
   }
   setEnvironment(environment);
   setResourceLoader(resourceLoader);
}
复制代码

3.3.14.7 ClassPathScanningCandidateComponentProvider#registerDefaultFilters();

protected void registerDefaultFilters() {
   // Component注解
   //过滤器中添加需要扫描的注解类型,把@Component注解添加进来
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
   ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
      logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
   }
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
      logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}
复制代码

image.png

Service也添加了@Component注解,所以@Service也能被扫描到

image.png

AnnotationTypeFilter用来包装需要扫描的注解的类型

image.png

3.3.14.8 回到3.3.14.5步,ComponentScanBeanDefinitionParser#parseTypeFilters(element, scanner, parserContext);

image.png

protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
   // Parse exclude and include filter elements.
   ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
   NodeList nodeList = element.getChildNodes();
   for (int i = 0; i < nodeList.getLength(); i++) {
      Node node = nodeList.item(i);
      if (node.getNodeType() == Node.ELEMENT_NODE) {
         String localName = parserContext.getDelegate().getLocalName(node);
         try {
            //  todo include-filter
            if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
               TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
               scanner.addIncludeFilter(typeFilter);
            }
            // todo exclude-filter
            else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
               TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
               scanner.addExcludeFilter(typeFilter);
            }
         }
         catch (ClassNotFoundException ex) {
            parserContext.getReaderContext().warning(
                  "Ignoring non-present type filter class: " + ex, parserContext.extractSource(element));
         }
         catch (Exception ex) {
            parserContext.getReaderContext().error(
                  ex.getMessage(), parserContext.extractSource(element), ex.getCause());
         }
      }
   }
}
复制代码

将需要被扫描到的注解和不要被扫描到的注解的类型,分别放到2个集合中

private final List<TypeFilter> includeFilters = new ArrayList<>();

private final List<TypeFilter> excludeFilters = new ArrayList<>();
复制代码

3.3.14.9 回到3.3.14.4步, ClassPathBeanDefinitionScanner#doScan(String… basePackages)

public BeanDefinition parse(Element element, ParserContext parserContext) {
  ...
   // todo 创建注解扫描器
   // Actually scan for bean definitions and register them.
   ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
   // todo 扫描并把扫描的类封装成beanDefinition对象  核心方法,重要程度 5
   Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
   // 如果加了@Component的类中,又加了@Autowired、@Value、@Resource、@PostConstruct、@PreDestroy注解,使用这个方法就可以扫描得到
   // 在Bean的实例化过程中有至关重要的作用
   registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

   return null;
}
复制代码
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   for (String basePackage : basePackages) {
      // 找到候选组件,需要扫描需要扫描的组件
      // todo 扫描到有注解的类并封装成BeanDefinition对象
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            //支持了@Lazy @DependOn注解
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            // todo BeanDefinition注册
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}
复制代码

3.3.14.10 ClassPathScanningCandidateComponentProvider#findCandidateComponents(String basePackage)

componentsIndex一般情况下都为null,所以会走else

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
      // todo 扫描所有组件
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      // todo
      return scanCandidateComponents(basePackage);
   }
}
复制代码

3.3.14.11 ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      //这里递归寻找文件,所有的.class文件
      Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
      boolean traceEnabled = logger.isTraceEnabled();
      boolean debugEnabled = logger.isDebugEnabled();
      for (Resource resource : resources) {
         if (traceEnabled) {
            logger.trace("Scanning " + resource);
         }
         try {
            //扫描类里的信息放在MetadataReader对象中
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
            //判断类上面是否有includeFilters集合内包含的注解
            if (isCandidateComponent(metadataReader)) {
               //根据MetadataReader 对象内的类的基本信息,包装成BeanDefinition对象
               ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
               sbd.setSource(resource);
               if (isCandidateComponent(sbd)) {
                  if (debugEnabled) {
                     logger.debug("Identified candidate component class: " + resource);
                  }
                  candidates.add(sbd);
               }
               else {
                  if (debugEnabled) {
                     logger.debug("Ignored because not a concrete top-level class: " + resource);
                  }
               }
            }
            ...
         }
         ...
      }
   }
   ...
   return candidates;
}
复制代码

AnnotationMetadata对象内有类的所有信息,方法、属性、注解等

image.png

image.png

3.3.14.12 回到3.3.14.9步,ClassPathScanningCandidateComponentProvider#registerBeanDefinition(definitionHolder, this.registry)

BeanDefinition注册: image.png

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
复制代码

和默认标签解析的注册方法,3.3.13.12步一模一样, DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   // todo  完成BeanDefinition的注册,重点看,重要程度 5
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   // 建立别名和 id的映射,这样就可以根据别名获取到id
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}
复制代码

3.3.14.13 回到3.3.14.9步,ComponentScanBeanDefinitionParser#registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

  • 如果加了@Component的类中,又加了@Autowired、@Value、@Resource、@PostConstruct、@PreDestroy注解,使用这个方法就可以扫描得到
  • 在Bean的实例化过程中有至关重要的作用

image.png

4. 总结

obtainFreshBeanFactory()方法:

  1. 创建XmlBeanDefinitionReader对象
  2. Reader通过xml文件路径加载配置文件,转换成Resource对象类型
  3. 把Resource对象封装成document对象
  4. 创建BeanDefinitionDocumentReader对象,负责对document对象解析
  5. 根据namespace判断走默认标签解析还是自定义标签解析
  6. parseDefaultElement(ele, delegate);负责常规标签解析
    • 6.1、解析document对象并包装成BeanDefinition对象
    • 6.2、再将BeanDefinition封装成BeanDefinitionHolder返回
    • 6.3、对BeanDefinitionHolder对象进行装饰,解析属性标签或者构造方法标签
    • 6.4、通过SPI加载所有"META-INF/spring.handlers"文件,建立映射关系,找到namespaceUri对应的实现了NamespaceHandler接口的处理类,通过反射实例化处理类,并强转为NamespaceHandler,调用处理类的init方法,完成标签元素解析类的注册;调用NamespaceHandler类的decorate装饰
    • 6.5、registerBeanDefinition对BeanDefinition进行注册,加入到beanDefinitionMap和beanDefinitionNames
  7. delegate.parseCustomElement(ele);负责自定义标签解析
    • 7.1. 通过SPI找到自定义标签的处理类,调用init方法,完成标签元素解析类的注册,建立标签和解析类的映射关系
    • 7.2. 调用ComponentScanBeanDefinitionParser的parse方法,
    • 7.3. 创建注解扫描器,使用默认的过滤器,把需要被扫描到的注解和不要被扫描到的注解的类型添加进来
    • 7.4. 递归扫描路径下所有.class后缀的文件,把类的信息放在MetadataReader对象中,判断类上面是否包含我需要的注解,封装成BeanDefinition对象
    • 7.5. 完成BeanDefinition的注册

参考文章

Spring5源码注释github地址
Spring源码深度解析(第2版)
spring源码解析
Spring源码深度解析笔记
Spring注解与源码分析
Spring注解驱动开发B站教程

猜你喜欢

转载自juejin.im/post/7132658819678601247
今日推荐