spring源码学习 - 注解bean的解析注册过程

解析方式

上一篇文章中提到spring初始化进行配置解析的时候会根据命名空间来选择不同的解析方式

  • 当命名空间是"http://www.springframework.org/schema/beans"时选择默认的解析方式进行解析
  • 其他类型会选择自定义的方式进行解析. 比如:

<context:component-scan>的命名空间是:http://www.springframework.org/schema/context
<task:executor>的命名空间是:"http://www.springframework.org/schema/task"
<aop:aspectj-autoproxy>的命名空间是:"http://www.springframework.org/schema/aop"

配置扫描器

当我们要使用@service @Repository @Component ,通常需要配置一个扫描器类似

回到问题

当在一个javaBean上标注@service时spring初始化做了什么?

下面开始debug源码
  1. 创建javaBean并进行@service标注


    Paste_Image.png
  2. 准备单元测试类


  3. 跟踪源码来到DefaultBeanDefinitionDocumentReader中的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate):
    Paste_Image.png
  4. 循环解析过程中节点对象Element命名空间为http://www.springframework.org/schema/context的时候开始进入自定义解析模式 ,最后来到BeanDefinitionParserDelegate中的parseCustomElement(Element ele, BeanDefinition containingBd)方法:
    Paste_Image.png
  5. 看下spring获取解析处理器的过程,整个过程非常的简单粗暴:直接解析spring类路径下所有的META-INF/spring.handlers配置文件,然后放入map当中.注意下这里的map中的key实际上String类型的,只有当该处理器第一次被使用的时候才会通过反射创建出真实的处理器对象

  6. 到这里,spring对于自定义bean的解析和注册开始委托给了NamespaceHandler类,最终被委托给了ComponentScanBeanDefinitionParser,主要分为三个过程:
  • 处理我们在配置文件中定义的扫描路径
  • 扫描出所有的注解bean,并进行注册
  1. 进入Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);,生成容器数据对象并进行注册,主要分三个过程:
  • 扫描类路径下符合要求的class,获取class的元数据,组装基础容器数据对象ScannedGenericBeanDefinition,
  • 设置一系列的属性
  • 向容器进行注册,到这里就完成注解bean的注册
  1. 回到上一步看到还有registerComponents(parserContext.getReaderContext(), beanDefinitions, element)这一个过程,为什么要有这个过程呢?因为单单注册我们注解定义的bean还不够,还会涉及到一些内部依赖处理器bean也要进行构建和注册,因为bean的内部还可以依赖另一个bean,可以看一下整个注册过程完成后容器中DefaultListableBeanFactory.beanDefinitionMap结构
    Paste_Image.png
参考资料

推荐阅读更多精彩内容