spring的IOC源码解读

本文深入探讨了 Spring IoC 容器的核心概念、设计原理及实现过程,包括依赖反转、BeanFactory 和 ApplicationContext 的使用,以及 BeanDefinition 的定义与初始化流程。重点介绍了 IOC 容器如何管理依赖关系,实现对象之间的解耦,最终完成对象的实例化和初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                                         spring IOC

spring的整体结构如下图


依赖反转(IOC Dependency Inversion Principle:在编码过程中,对象封装了数据和数据的处理,在对数据处理过程中,需要引用其他一个类或者多个类的方法来处理,那么这些类的引入过程要靠自身的类要实现,那么会导致代码高度耦合。在spring中引入了IOC容器来管理这些依赖的BEANIOC容器可以在对象生成或者初始化时直接将数据注入到对象中(例如对象中注入LIST数据集),也可以将对象引用注入到对象数据域中的方式来注入对方法调用的依赖,这种依赖注入是可以递归的,对象被逐层注入,这样把对象依赖关系有序串起来,简化依赖管理。

控制反转是关于一个对象如何获取它所依赖的对象的引用。

 

IOC容器系列的设计和实现  BeanFactory 和 ApplicationContext

 

springIOC容易包含两类:1.实现BeanFactory接口的简单容器,

                              这系列容器只实现了容器的基本功能。

                           2.ApplicationContext应用上下文,作为容器的高级形态存在。

 增加了很多面向框架的特性。

BeanFactory为功能规范的设计表现接口,规范了Spring提供给用户使用的IOC容器所设定的最基本的功能规范,所有的Spring容器必须满足BeanFactory这个基本接口的定义。

 

BeanDefinition:抽象了对Bean的定义,描述了一个bean实例,包括依赖对象,属性值,构造方法参数值,类加载器和继承类父类,工厂构造类,工厂构造方法等,BeanDefinition只是一个简单的接口,是容器实现依赖反转功能的核心数据结构,依赖反转功能都是围绕对个BeanDefinition的处理来完成的。

其继承关系如下:

BeanMetadataAttributeAccessor :为对属性的一个操作,get,set,remove

AttributeAccessorSupport:private final Map<String, Object> attributes = new LinkedHashMap<String, Object>(0);使用这个MAP来封装属性以及相关的值。

 

Spring IOC容器的设计

<!--EndFragment-->



 

1.简单容器:从BeanFactoryHierarchicalBeanFactory,再到ConfigurableBeanFactory.

  BeanFactory的接口定义了基本IOC容器的规范,而HierarchicalBeanFactory,增加了

getParentBeanFactory方法获取双亲IOC容器的功能,ConfigurableBeanFactory中主要增加对BeanFactory的配置功能。

通过对这些接口的叠加,形成一个简单的容器功能。

2.ApplicationContext应用上下文接口为核心的接口设计。

 从BeanFactoryListableBeanFactory,再到ApplicationContext,再到WebApplicationContext或者是ConfigurableApplicationContext,我们常用的应用上下文基本上都是WebApplicationContext或者是ConfigurableApplicationContext的接口实现,其中ListableBeanFactory定义了对BeanDefinitionBean的一些获取,设置操作。

WebApplicationContext定义了一些WEB使用的常量,以及获取ServletContext getServletContext()方法。

ConfigurableApplicationContext里面增加了环境配置相关的方法,例如增加了

void addApplicationListener(ApplicationListener<?> listener);应用监听机制。

 

以上都是接口定义体系,而具体的IOC容器都是在这个接口体系下实现的。

例如简单容器 DefaultListableBeanFactory,这个



 

BeanFactory , FactoryBean的区别,这两个在Spring中使用频率很高,在此先做一个区分和说明

Spring容器中,所有的Bean都是由BeanFactory (也就是IOC容器)来管理的,但是对FactoryBean,这个Bean不是简单的Bean,而是一个能生成或者修饰对象生成的工厂Bean,跟工厂模式和修饰模式类似。

BeanFactory :定义了一系列的接口方法,通过这些接口,可以使用不同的Bean的检索,很容易的从IOC容器中得到需要的Bean,从而忽略具体的IOC容器。

下面说一下IOC容器的设计原理

使用XMLBeanFactory做一个说明,具体的关系如下图

 

XmlBeanFactory继承了DefaultListableBeanFactory这个类,

DefaultListableBeanFactory已经包含了基本IOC容器所具有的重要功能,在Spring中,实际上是把DefaultListableBeanFactory当做默认的功能完善的IOC容器来使用。

XmlBeanFactory中增加了XmlBeanDefinitionReader来读取资源文件数据,构造XmlBeanFactory时,需要制定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类给出,ResourceSpring用来封装I/O操作的类。例如

ClassPathResource res = new ClassPathResource (bean.xml),由具体的ClassPathResource 来构造Resource,然后将Resource作为参数传递给XMLBeanFactory构造函数,这样IOC容器就可以方便定位到需要的BeanDefinition信息,这样对Bean完成容器的初始化和依赖注入过程。

ClassPathResource res = new ClassPathResource("bean.xml");

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

1> 创建IOC配置文件的抽象资源,这个抽象资源包含了BeanDefinition的定义信息。

2》创建一个BeanFactory,这里使用DefaultListableBeanFactory 

3》创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML形式的BeanDefinition,通过一个回调配置给BeanFactory

4》从定义好的资源位置读入配置信息,完成整个载入和注册Bean定义之后,需要的IOC容器就建立起来了。

 

ApplicationContext的应用场景

 

除了相比简单的BeanFactory基本IOC容器,还提供很多附加功能

 1》支持不同的信息源。由于ApplicationContext扩展了MessageSource接口,这样可以支持国际化,开发多语言版本的应用提供服务。

2》访问资源,这一特性体现在对ResourceLoaderResource的支持上,可以从不同地方获取Resource,具体的ApplicationContext都是继承了DefaultResourceLoader的子类

3》支持应用事件。继承了接口ApplicationEventPublisher,从而在上下文中引入了事件机制。

 

IOC容器的初始化过程

简单来说IOC容器的初始化时由Refresh方法来启动的,这个方法标志IOC容器的正式启动,具体来说,这个启动包括BeanDefinitionResource定位,载入和注册三个基本过程

1Resource定位过程,由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用提供了统一接口

2BeanDefinition的载入,把用户定义好的Bean表示成IOC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。,具体来讲,这个BeanDefinition实际上就是POJO对象在IOC容器的抽象,通过这个BeanDefinition定义的数据结构,是IOC容器能够方便地对POJO对象也就是Bean进行管理。

3》向IOC容器注册这些BeanDefinition的过程,这个过程是通过调用BeanDefinitionRegister接口的实现来完成的。这个注册过程把载入过程中解析得到的BeanDefinitionIOC容器进行注册,通过代码分析可以看到,在IOC容器内部将BeanDefinition注入到一个HashMAP中去,IOC容器就是通过这个HashMAP来持有这些BeanDefinition数据的。

 

 

BeanDefinitionResource定位

FileSystemXmlApplicationContext做一个实例来说明这个Resource的定位过程

<!--EndFragment-->

 

 

从图上可以看到FileSystemXMLApplication已经通过继承AbstractApplicationContext具备了ResourceLoader读入以Resource定义的BeanDefinition的能力,  Spring内部,针对于资源文件有一个统一的接口Resource表示。其主要实现类有ClassPathResourceFileSystemResourceUrlResourceByteArrayResourceServletContextResourceInputStreamResource

 

这个RefreshBeanFactory方法被FileSystemXMLApplicationContext构造函数的Refresh方法调用,在这个方法中,通过createBeanFactory构建了一个IOC容器(DefaultListableBeanFactory)供ApplicationContext使用,同时,它启动了loadBeanDefinition来载入BeanDefinition

具体的资源载入在XMLBeanDefinitionReader读入BeanDefinition时完成,在XMLBeanDefinitionReader的基类AbstractBeanDefinitionReader中有这个实现过程。

AbstractXmlApplicationContext中有

 

这样就完成了Resource的定位。

<!--EndFragment-->

BeanDefinition的载入和解析

 

载入过程,相当于把定义的BeanDefinitionIOC容器中转换成一个IOC内部表示的数据结构的过程。IOC容器对Bean的管理和依赖注入功能的实现,是通过对其持有的BeanDefinition进行各种相关操作来完成的。这些BeanDefinition数据在IOC容器中通过一个HashMap来保持和维护。

AbstractApplicationContext类中,可以看到整个启动过程,其中在

obtainFreshBeanFactory()方法中已经完成Resource的加载

AbstractXMLApplicationContext中的loadBeanDefinition中,初始化了读取器XMLBeanDefinitionReader,让读取器来完成BeanDefinitionIOC容器的载入。

 具体的载入是在AbstractBeanDefinitionReader载入

 但是调用loadBeanDefinitions(Resource resources)方法是在XMLBeanDefinitionReader中实现的,这样读取XML文件的IO操作对象,有了这些文件对象后,就可以按照spring的bean定义规则来对这个XML的文档进行解析了。

<!--EndFragment-->

XmlBeanDefinitionReader

 BeanDefinition的载入分两部分,首先通过调用XML的解释器得到Document对象,再按照SpringBean规则进行解析,处理的结果由BeanDefinitionHolder对象持有,这个对象除了持有BeanDefinition,还有Bean的名称,别名集合等。

 

解析文档是由BeanDefinitionParseDelegate来完成, 解析为BeanDefinition形式

 其中详细解析XML文件中方法如下:

 对于BeanDefinition中的Property元素的处理

 获取Property元素的值,也许是一个List



 


 

对于Array,List,Set,Map,Prop等各种元素都是由Managed类对SpringBeanDefinition的数据的封装,例如 ManagedListManagedArrayManagedSet

这样经过逐层解析,在XML文件中定义的BeanDefinition就被整个载入到了IOC容器中,并在容器中建立了数据映射

那么解析后的数据存储是一个什么过程呢?

 

那么解析后的值通过

DefaultBeanDefinitionDocumentReader.java类的



BeanDefinitionReaderUtils.java

<!--EndFragment--><!--EndFragment-->

 

 回调DefaultListableBeanFactory容器的方法

<!--EndFragment-->

 


IOC容器的依赖注入

用户第一次向IOC容器获取Bean或者设置lazy-init属性来触发依赖注入。

调用DefaultListableBeanfactory的基类AbstractBeanFactorygetBean方法

<!--EndFragment--> 

 

总体来说,getBean是依赖注入的触发点,之后调用createBeanbean对象的生成是依赖BeanDefinition定义的要求生成,AbstractAutowireCapableBeanFactory实现这个过程

<!--EndFragment-->



  

doCreateBean中可以看看Bean的生成

<!--EndFragment-->



  

 

 

依赖注入关系特别密切的方法有createBeanInstancepopulateBean

下面分别对这些方法说明一下

<!--EndFragment-->



  

 

使用默认的构造函数对Bean进行实例化

<!--EndFragment-->

 

 

IOC容器中使用CGLIB生成Bean对象,可以看看SimpleInstantiationStrategy

<!--EndFragment-->

 

 

 

在这里已经分析了实例化Bean对象的整个过程,在实例化Bean对象生成的基础上,对Bean对象的依赖关系设置好,完成整个依赖注入的过程。依赖关系处理的依据就是BeanDefinition,现在对前面的populateBeanAbstractAutowireCapableBeanFactory类中)方法解析

<!--EndFragment-->

 

 

 

 

具体的属性依赖注入是在BeanWrapperImplement中实现的

<!--EndFragment-->

 

 

 

 

这样就完成了各种Bean属性的依赖注入过程

另外一个注意要点

<!--EndFragment-->


1.配置主类为 prototype那么引用类SayOp为单列

<!--EndFragment-->  

 

 

1.配置主类为单列,引用类SayOpprototype

运行结果为



在此说明一个问题,在单列模式下面的引用类配置prototype类型是没有用的。

<!--EndFragment--><!--EndFragment--><!--EndFragment--><!--EndFragment-->
<think>好的,我现在需要帮助用户理解Spring IOC容器的源码实现和工作原理。用户之前已经提供了一些相关的引用内容,我需要结合这些内容来组织一个清晰且详细的回答。 首先,我应该先回顾用户提供的引用,找出关键点。引用1提到BeanFactory和ApplicationContext是两个核心接口,需要分析它们的源码差异。引用2提到了IoC容器的基本概念、关键接口、bean的生命周期和循环依赖的解决方法。引用3提到了事件发布器和监听器的初始化,这部分涉及观察者模式。引用4是关于prepareRefresh方法的预处理步骤,包括初始化属性和早期事件处理。引用5提到了Bean工厂后置处理器和Bean实例化的完成。 接下来,我需要确定回答的结构。通常,源码分析可以从容器启动流程、Bean生命周期管理、核心接口差异、设计模式应用等方面展开。用户的问题比较广泛,所以需要覆盖主要部分,同时保持结构清晰。 第一步,容器启动流程。根据引用4中的prepareRefresh方法,这是刷新前的预处理步骤,包括设置启动时间、状态,初始化属性,验证环境变量,保存早期事件。然后,引用5中的invokeBeanFactoryPostProcessors和finishBeanFactoryInitialization是后续步骤,处理Bean工厂后置处理器和实例化Bean。需要详细说明这些步骤的顺序和作用。 第二步,Bean的生命周期管理。这里需要结合BeanFactory和ApplicationContext的区别,可能涉及Bean的创建、初始化、依赖注入、销毁等阶段。引用2中提到bean的生命周期是一个重点,可能需要详细描述每个阶段涉及的接口和方法,比如BeanPostProcessor。 第三步,关键接口分析。BeanFactory作为基础接口,而ApplicationContext扩展了更多功能,如事件发布、国际化等。引用1和引用2都提到了这两个接口,需要比较它们的源码和功能差异,比如ApplicationContext如何继承BeanFactory并添加额外特性。 第四部分,设计模式的应用。例如,观察者模式在事件处理中的应用,如引用3中的事件发布器和监听器的初始化。可能还有工厂模式在Bean创建中的使用,单例模式在Bean作用域中的应用等。 第五部分,解决循环依赖。引用2提到循环依赖是高级特性,需要解释Spring如何通过三级缓存解决这个问题,可能涉及源码中的DefaultSingletonBeanRegistry类中的getSingleton方法及相关处理。 在组织内容时,要确保每个部分都有对应的源码引用和解释,例如在容器启动流程中,可以引用prepareRefresh的代码片段,说明其作用。同时,结合用户提供的引用,正确标注引用标识,如[^4]、[^5]等。 另外,用户可能需要示例代码或流程图来辅助理解,但根据问题描述,用户要求的是文本回答,所以需要用清晰的步骤和子标题来划分内容。比如使用“1. 容器启动流程”、“2. Bean生命周期管理”等。 最后,生成相关问题,可能需要围绕源码分析、设计模式、具体实现细节等方面提问,例如询问BeanFactory和ApplicationContext的区别,或者如何扩展BeanPostProcessor接口。 需要确保回答符合用户的要求:结构清晰,分步骤解释,引用正确,并且使用中文。同时,避免使用Markdown格式,但根据用户提供的示例,可能需要使用代码块来展示源码片段,如引用4中的prepareRefresh方法代码。 现在需要整合这些思路,形成一个连贯的回答,涵盖用户提到的所有关键点,并正确引用提供的参考文献。</think>### Spring IOC 源码分析及详细解读 #### 一、容器启动流程 Spring IOC 容器的启动流程围绕 `ApplicationContext` 的 `refresh()` 方法展开,核心步骤如下: 1. **预处理阶段 (`prepareRefresh()`)** - 记录启动时间,设置容器状态为激活。 - 初始化环境变量和配置参数(如 `initPropertySources()`)。 - 验证必要属性是否合法(如 `validateRequiredProperties()`)。 - 准备早期事件存储队列 `earlyApplicationEvents` [^4]。 2. **加载Bean定义 (`obtainFreshBeanFactory()`)** - 创建 `BeanFactory`(默认实现为 `DefaultListableBeanFactory`)。 - 解析 XML 或注解配置,将 Bean 定义注册到 `BeanDefinitionMap` 中。 3. **处理后置处理器 (`invokeBeanFactoryPostProcessors()`)** - 调用 `BeanFactoryPostProcessor` 实现类(如 `ConfigurationClassPostProcessor`),完成配置类解析、`@Bean` 方法解析等[^5]。 4. **初始化事件和监听器** - 通过 `initApplicationEventMulticaster()` 初始化事件广播器。 - 通过 `registerListeners()` 注册监听器,支持观察者模式[^3]。 5. **实例化单例Bean (`finishBeanFactoryInitialization()`)** - 遍历 `BeanDefinitionMap`,对非懒加载的单例 Bean 进行实例化、依赖注入和初始化[^5]。 --- #### 二、Bean生命周期管理 Bean 的生命周期由以下接口控制: ```java // 示例代码:Bean生命周期关键接口 public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName); Object postProcessAfterInitialization(Object bean, String beanName); } ``` 1. **实例化**:通过反射调用构造函数。 2. **属性注入**:通过 `populateBean()` 方法注入依赖(如 `@Autowired`)。 3. **初始化**: - 调用 `InitializingBean.afterPropertiesSet()`。 - 执行自定义初始化方法(如 `@PostConstruct`)。 4. **销毁**:容器关闭时调用 `DisposableBean.destroy()` 或自定义销毁方法。 --- #### 三、核心接口对比:BeanFactory vs ApplicationContext | 特性 | BeanFactory | ApplicationContext | |---------------------|---------------------------|----------------------------------------| | Bean实例化 | 延迟加载 | 支持预加载(通过 `refresh()` 触发) | | 国际化支持 | 无 | 有(`MessageSource`) | | 事件发布 | 无 | 有(`ApplicationEventPublisher`) | | AOP集成 | 需手动配置 | 自动集成 | | 资源访问 | 基础支持 | 扩展支持(如 `ResourceLoader`) | ApplicationContext 通过组合模式扩展了 BeanFactory 的功能[^1]。 --- #### 四、设计模式应用 1. **工厂模式**:`BeanFactory` 是工厂接口,`DefaultListableBeanFactory` 是具体实现。 2. **观察者模式**:事件广播器 (`ApplicationEventMulticaster`) 和监听器 (`ApplicationListener`) 实现解耦[^3]。 3. **模板方法模式**:`AbstractApplicationContext.refresh()` 定义了容器刷新的步骤骨架。 --- #### 五、循环依赖解决 Spring 通过**三级缓存**解决循环依赖: 1. **一级缓存** (`singletonObjects`):存放完全初始化的 Bean。 2. **二级缓存** (`earlySingletonObjects`):存放未完成属性注入的早期 Bean 引用。 3. **三级缓存** (`singletonFactories`):存放 Bean 工厂对象,用于生成早期代理对象。 源码关键方法: ```java // DefaultSingletonBeanRegistry 类 protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值