Spring 源码分析总结篇一: Spring IOC篇

一、前言

本文,是本人在阅读源码过程中的一些内容整理和总结。
全文仅代表个人理解和意见,故难免出现错误,如若发现,欢迎指正。十分谢谢。

本文所涉及的文章内容均在 : Spring源码分析:全集整理


关于 :ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessor 的详细分析,可以在 Spring源码分析:全集整理 中找到对应的分析文章。

二、正文

1. Spring IOC 实现个人感觉最重要的两个类

  • ConfigurationClassPostProcessor : 完成了类的扫描和配置了的解析

  • AutowiredAnnotationBeanPostProcessor : 完成了非 Property 的属性的注入


  1. ConfigurationClassPostProcessorBeanFactoryPostProcessor子类。完成了对Bean的解析,生成的对应的BeanDefinition。

    postProcessBeanDefinitionRegistry : 解析所有需要注册的配置类
    postProcessBeanFactory :对Full类型进行代理增强,保证@Bean方法正确语意。

  2. AutowiredAnnotationBeanPostProcessorBeanPostProcessor 子类,完成了@Autowired、@Value、@Inject注解的解析注入功能。也就是说 AutowiredAnnotationBeanPostProcessor 中才完成了属性的注入。

2. Spring什么时候扫描的包路径?

Spring在启动时候会将启动类注册到Spring容器中。在ConfigurationClassPostProcessor中,会将启动类作为配置类进行解析。由于启动类上面有@ComponentScan注解,所以在ConfigurationClassParser# doProcessConfigurationClass中会解析这个注解, 根据解析后的路径通过
his.componentScanParser, parse (componentScan,sourceClass.getMetadata () .getClassName())进行扫描,注册扫描到的需要注入的类(被@Component 修饰的类)并进行注入,如果有配置类再进行递归的配置类解析。(扫描是在 方法 org.springframework.context. annotation.ClassPathBeanDefinitionScanner#doScan中进行的扫描,但是我偷懒了没看具体实现)

3. ConfigurationClassPostProcessor 的解析流程

.ConfigurationClassPostProcessor完成了对各种配置类的扫描,并将其引入的bean注册到BeanFactory中。

  1. postProcessBeanDefinitionRegistry方法逻辑(完成了各种配置类的解析和注册)

  2. 获取所有BeanFactory中的BeanDefinition

  3. 遍历所有BeanDefinition,筛选出full或者lite 配置类,等待下一步处理。

    • Full 规则 :被 @Configuration 注解修饰 && proxyBeanMethods属性为true (默认为true)
    • Lite规则:被@Component. @ComponentScan, @Import. @ImportResource修饰的类或者类中有被@Bean修饰的方法(该方法会被包装成一个 BeanDefinition)
  4. 遍历所有full 和lite配置类,解析各种注解,对配置类进行进一步的解析(因为Lite的配置类需要二次解析,所以这里主要是二次解析)

    • @Component进行解析:即如果当前配置类被@Component注解修饰,则去解析其内部类(包括静态内部类和非静态内部类)是否是配置类,如果是,递归解析发现的配置类。
    • :对@PropertySource进行解析:解析出其指定的配置文件内容,并保存到environment 中
    • :对@ComponentScan注解的解析:获取注解指定路径,进行扫描注册。对新扫描出来的BeanDefinition进行判定是否是配置类,如果是,则递归去解析配置类
    • @Import、ImportSelector、ImportBeanDefinitionRegistrar的解析:因为这三个注解或接口,本质上完成的功能是.一样的,都是引入类。所以在这一部分的处理上只是区分了不同的类型
    • @ImportResource注解的解析:提取出@ImportResource注解的属性,保存到configClassimportedResources属性中
    • 对被@Bean修饰的方法的解析:提取出@Bean修饰的方法,保存的到configClassbeanMethods属性中.
    • 对接口的默认方法解析:保存的到configClassbeanMethods属性中
    • 对父类的解析:如果存在父类,则递归其父类进行解析。
  5. 遍历所有的配置类,进行注册

    • 处理引入的配置类:将配置类信息封装成BeanDefinition,并注册到BeanFactory
    • 处理@Bean修饰的方法将@Bean修饰的方法封装成BeanDefinition,并注册到BeanFactory
    • 处理@ImportResource注解引入的资源文件,获取到BeanDefinition并注册。
    • 处理@Import、ImportSelector、ImportBeanDefinitionRegistrar引入的类,注册到BeanFactory中。

补充:4.1 中为什么要解析@Component?

  • 因为过滤出来的配置类可能没有被@Component修饰,比如仅仅是,可能是Spring硬编码注入或者我们通过编码注入的bean。如果没有使用@Component注解修饰,就没必要解析其内部类是否是配置类。比如最简单的就是spring.factories文件中引入的类。可能满足配置类判定,但并没有被@Component修饰

4. AutowiredAnnotationBeanPostProcessor 的解析流程

AutowiredAnnotationBeanPostProcessor 完成@Autowired. @Value、 @Inject注解的功能, 完成了
Spring的注入

  1. determineCandidateConstructors 方法 :筛选出当前bean中能作为构造注入的构造函数列表。用于构造注入

    • 处理了@Lookup注解,将@Lookup注解标注的方法保存了起来。这一步和构造函数的筛选没有任何关系
    • 挑选候选构造函数。简单逻辑就是有注解修饰选注解修饰的构造函数,没有的话使用默认无参构造函数没有无参构造函数,再没有返回null.
  2. postProcessProperties 方法 :筛选Bean中需要注入的属性,进行属性注入。用于设置注入和注解注入遍历每个属性,找到被注入注解修饰的属性。保存到currElements中。遍历每个方法,找到被注入注解修饰的方法, 保存到currElements中。随后遍历currElements, 通过resolveDependency方法将方法或者属性注入(resolveDependency方法是在populateBean方法中按照类型注入时调用的方法)这里可以知道,按照顺序遍历,方法的属性在属性的后面,自动注入时,方法的注入结果会把注解属性的注入覆盖掉。

注: Spring注入的方式分为三种 :构造注入、设值注入、注解注入。在AutowiredAnnotationBeanPostProcessor 中处理的实际是设置注入和注解注入。

5. Bean 创建的过程

个人认为,在Spring容器中Bean的 创建时可以认为分为两个过程:

  1. Bean对应的BeanDefinition 的创建。
  2. Bean 实例的创建。

那么提出下面的问题:

  • BeanDefinition 的作用是什么?为什么需要创建 BeanDefinition?

    因为在 Spring容器中,Bean的创建并非仅仅通过反射创建就结束了。在创建过程中,需要考虑到Bean针对Spring容器中的一些属性,如 Bean的作用域(单例、多例等),是否需要懒加载、Bean是否使用别名等。所以BeanDefinition 中不仅仅包含了 Bean Class 文件信息,还包含了这些容器属性。当Bean 进行实例化创建时需要根据对应的BeanDefinition 提供对应的信息来完成创建过程。

  • BeanDefinition 是在什么时候创建的?

    ConfigurationClassPostProcessor 在解析出需要注入的Bean的同时会生成对应的 BeanDefinition,并保存到 DefaultListableBeanFactory#beanDefinitionMap

  • Bean 的实例在什么时候创建的?

    这里需要分为两种情况:BeanPostProcessor 和普通的Bean。BeanPostProcessor 因为参与在普通Bean的创建过程,所以其创建时机在普通Bean之前。不过都在AbstractApplicationContext#refresh 中创建,详细实现我们在Spring源码分析一:容器的刷新 - refresh() 中讲过。其大概逻辑如下:

    public void refresh() throws BeansException, IllegalStateException {
    	...
    	// 激活 BeanFactoryPostProcessors
    	invokeBeanFactoryPostProcessors(beanFactory);
    	...
    	// 创建 BeanPostProcessor 实例并注册到 BeanFactory.beanPostProcessors 集合中
    	registerBeanPostProcessors(beanFactory);
    	...
    	// 完成非惰性普通bean的创建工作
    	finishBeanFactoryInitialization(beanFactory);
    	...
    }
    
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫吻鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值