Notes-SpringIOC(控制反转)-《Java笔记》

admin 2025-10-19 04:23:23 编程 来源:ZONE.CI 全球网 0 阅读模式

Spring IOC Spring容器的顶层接口是:BeanFactory,但使用更多的是它的子接口:ApplicationContext。通常情况下,如果想要手动初始化通过xml文件配置的Spring容器时,代码是这样的:

  1. ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");User user = (User)applicationContext.getBean("name");

如果想要手动初始化通过配置类配置的Spring容器时,代码是这样的:

  1. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);User user = (User)applicationContext.getBean("name");

这两个类应该是最常见的入口了,它们却殊途同归,最终都会调用refresh方法,该方法才是Spring容器初始化的真正入口。Spring IOC(控制反转) - 图1Spring IOC(控制反转) - 图2其实调用refresh方法的类并非只有这两个,用一张图整体认识一下:Spring IOC(控制反转) - 图3虽说调用refresh方法的类有这么多,这里用ClassPathXmlApplicationContext类作为列子进行分析,因为它足够经典,而且难度相对来说要小一些。

refresh方法

refresh方法是spring ioc的真正入口,它负责初始化Spring容器。既然这个方法的作用是初始化Spring容器,那方法名为啥不叫init?答案很简单,因为它不只被调用一次。在SpringBoot的SpringAppication类中的run方法会调用refreshContext方法,该方法会调用一次refresh方法。在SpringCloud的BootstrapApplicationListener类中的onApplicationEvent方法会调用SpringAppication类中的run方法。也会调用一次refresh方法。

这是SpringBoot项目中如果引入了SpringCloud,则refresh方法会被调用两次的原因。

springmvcFrameworkServlet类中的initWebApplicationContext方法会调用configureAndRefreshWebApplicationContext方法,该方法会调用一次refresh方法,不过会提前判断容器是否激活。所以这里的refresh表示重新构建的意思。重点看看refresh的关键步骤:Spring IOC(控制反转) - 图4其实上图中一眼看过去好像有很多方法,但是真正的核心的方法不多,其中最重要的:

  • obtainFreshBeanFactory
  • invokeBeanFactoryPostProcessors
  • registerBeanPostProcessors
  • finishBeanFactoryInitialization

    解析xml配置文件

    obtainFreshBeanFactory方法会解析xml的bean配置,生成BeanDefinition对象,并且注册到Spring容器中(就是很多map集合中)。经过几层调用,会调到AbstractBeanDefinitionReader类的loadBeanDefinitions方法:Spring IOC(控制反转) - 图5该方法会循环locations(applicationContext.xml文件路径),调用另外一个loadBeanDefinitions方法,一个文件一个文件解析。经过一些列的操作,会将location转换成inputSourceresource,然后再转换成Document对象,方便解析。image.gif640.png在解析xml文件时,需要判断是默认标签,还是自定义标签,处理逻辑不一样:Spring IOC(控制反转) - 图8Spring的默认标签只有4种:

  • <import/>

  • <alias/>
  • <bean/>
  • <beans/>

对应的处理方法是:Spring IOC(控制反转) - 图9注意常见的:<aop/><context/><mvc/>等都是自定义标签。从上图中处理<bean/>标签的processBeanDefinition方法开始,经过一系列调用,最终会调到DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法。Spring IOC(控制反转) - 图10这个方法包含了关键步骤:解析元素生成BeanDefinition 和 注册BeanDefinition。

生成BeanDefinition

下面重点看看BeanDefinition是如何生成的。上面的方法会调用BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法:Spring IOC(控制反转) - 图11一个<bean/>标签会对应一个BeanDefinition对象。该方法又会调用同名的重载方法:processBeanDefinition,真正创建BeanDefinition对象,并且解析一系列参数填充到对象中:Spring IOC(控制反转) - 图12其实真正创建BeanDefinition的逻辑是非常简单的,直接new了一个对象:Spring IOC(控制反转) - 图13真正复杂的地方是在前面的各种属性的解析和赋值上。

注册BeanDefinition

上面通过解析xml文件生成了很多BeanDefinition对象,下面就需要把BeanDefinition对象注册到Spring容器中,这样Spring容器才能初始化bean。在BeanDefinitionReaderUtils类的registerBeanDefinition方法很简单,只有两个流程:Spring IOC(控制反转) - 图14先看看DefaultListableBeanFactory类的registerBeanDefinition方法是如何注册beanName的:Spring IOC(控制反转) - 图15接下来看看SimpleAliasRegistry类的registerAlias方法是如何注册alias别名的:Spring IOC(控制反转) - 图16这样就能通过多个不同的alias找到同一个name,再通过name就能找到BeanDefinition

修改BeanDefinition

上面BeanDefinition对象已经注册到Spring容器当中了,接下来,如果想要修改已经注册的BeanDefinition对象该怎么办呢?refresh方法中通过invokeBeanFactoryPostProcessors方法修改BeanDefinition对象。经过一系列的调用,最终会到PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法:Spring IOC(控制反转) - 图17流程看起来很长,其实逻辑比较简单,主要是在处理BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor。而BeanDefinitionRegistryPostProcessor本身是一种特殊的BeanFactoryPostProcessor,它也会执行BeanFactoryPostProcessor的逻辑,只是加了一个额外的方法。Spring IOC(控制反转) - 图18ConfigurationClassPostProcessor可能是最重要的BeanDefinitionRegistryPostProcessor,它负责处理@Configuration注解。

注册BeanPostProcessor

处理完前面的逻辑,refresh方法接着会调用registerBeanPostProcessors注册BeanPostProcessor,它的功能非常强大,后面的文章会详细讲解。经过一系列的调用,最终会到PostProcessorRegistrationDelegate类的registerBeanPostProcessors方法:Spring IOC(控制反转) - 图19注意,这一步只是注册BeanPostProcessor,真正的使用在后面。

总结

主要介绍了:

  1. Spring容器初始化的入口
  2. refresh方法的主要流程
  3. 解析xml配置文件
  4. 生成BeanDefinition
  5. 注册BeanDefinition
  6. 修改BeanDefinition
  7. 注册BeanPostProcessor
以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  0