Spring IOC底层分析

本文深入探讨Spring框架中IOC容器的初始化过程,包括Resource定位、BeanDefinition的载入与解析、BeanDefinition注册等核心环节,以及Bean实例化的时机与流程,帮助读者理解Spring的底层机制。

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

仅为面试准备,无法保证理解正确性,慎,欢迎纠正

前言

关于IOC底层的东西,我这里只是说一下大致的流程,不涉及具体的代码(能力有限).

正文

IOC初始化

  • IOC容器的初始化分为三个过程以及我们在使用spring时的代码对应(不是完全一一对应,这是顶层的方法,内部有较多的细节):

    • Resource定位:ClassPathReource resource = new ClassPathReource("bean.xml");
    • BeanDefinition的载入和解析: DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); , XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    • BeanDefinition注册: reader.loadBeanDefinition(resource);
    • 怎么理解BeanDefinition,可以将BeanDefinition在IOC初始化的地位看做是JVM中类的Class对象在类初始化中的地位,虽然二者没什么关系,但是好理解一些.
  • Reource定位

    • 主要是两个接口:ResourceSpring中的统一资源抽象接口;ResourceLoader是统一的资源加载抽象接口
    • 具体的方法实现不细说,只需要知道接口的具体实现类会将外部的资源加载到Spring中,当然是以被封装的形式存在.(resource->EncodedResource).最后会以EncodedResource对象的形式用于bean的后续初始化.
  • BeanDefinition的载入和解析

    • EncodedResource并不是直接就转换成BeanDefinition对象,而是要先转换成Document对象,然后再转换为BeanDefinition对象.这样做的原因也很简单,就是Document更方便.
    • 从EncodedResource到Document的转换过程有很多细节(比如文件解析器,错误处理,命名空间的问题),这里暂时将这个过程看做黑盒.
    • Document -> BeanDefinition的过程其实主要是和对Document的操作有关,也就是对xml标签的处理,有默认标签和自定义标签,不详细说.
  • 注册BeanDefinition

    • IOC是什么?在逻辑定义层面有很多形象通俗的解释,我见过最好的一篇是这个,这里我们说一下代码层面的,代码层面的IOC容器其实就是一些Map,有存储BeanDefinition的Map,有存储实例化后的单例Bean的Map等等.这里先说一下存储BeanDefinition的Map.
    • 这是一个ConcurrentHashMap,源代码如下:
      private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
      所谓注册,就是添加进入这个Map的过程,这里的key是beanName;
  • 初始化的过程就是这样,用一张图结束吧(copy来的):
    bean初始化

Bean实例化

  • 实例化时机分为很多种,一是使用BeanFactory和ApplicationContext的区别,二是Bean单例和多例的区别,三是单例情况下设置延迟加载的区别;
  • 如果是非延迟加载,那么会在容器启动时实例化bean.
  • 如果是延迟加载,那么Bean的加载就是第一次显示或隐式的调用getBean方法(该方法调用doGetBean方法),所以从这个方法开始:
    1. 转换beanName,因为getBean传入的name不一定是beanName,可能传入的是aliasNameFactoryBean
    2. 从缓存中获取bean,这里需要根据bean的作用域分一下情况:
      • 单例:spring的IOC只会保存一个对象实例,所有该对象的引用都共享这个实例,Spring容器只会创建唯一一个实例,保存在缓存中,并对该bean的后续请求和引用都会返回到该缓存的对象实例中.
      • 多例:每次对bean的请求都会返回一个新的实例
      • 其他
        • request : 每次http请求都会有一个bean实例
        • session: 一个session中,一个bean定义对应一个bean实例
      • 所以,从缓存中获取的bean一定是单例的,这里的缓存也是一个Map,名为singletonObjects,同层次还有两个Map,一个是earlySingletonObjects,另一个是singletonFactories.分别保存早期单例对象和bean工厂.之所以使用三个缓存,是为了解决bean之间的循环依赖.
    3. 缓存中没有找到的话,会在父容器的缓存中寻找
    4. 如果没有父容器或者父容器中也没有就会创建bean实例对象.这里的方法是createBean
      • 如果createBean维持的一个缓存中没有对应bean的beanWrapper,这里会先创建BeanWrapper,这是一个对要实例化Bean的包装.创建BeanWrapper的方法是createBeanInstrance,同时,这个方法也是非单例bean的创建实例的方法.使用的就是初始化时创建的BeanDefinition,大致的步骤就是确定构造方法,然后实例化.实现起来有很多细节,比如如果有动态代理,就需要使用cglib来实例化,否则使用反射实例化.
      • 回到createBean方法,得到BeanWrapper对象后,就要进行一系列的处理,主要是属性注入和循环依赖的处理.然后初始化Bean.
      • 初始化Bean主要是为了完成用户设定,例如激活Aware方法,应用后置处理器方法,激活自定义的方法.
    5. 得到了bean实例,但是并没有结束,无论是从单例缓存中获取的或者createBean中创建的bean,都只是bean实例,还需要从bean实例中获取对象.这里很难理解,bean实例难道不是对象吗,我看的博客中都是这样说的,但是从我的理解来看,这里的bean实例其实是FactoryBean实例,不知道FactoryBean的可以了解一下.总之,最后需要从FactoryBean中拿到对象,其实就是调用了getObject方法,不过框架嘛,你懂得,总是需要处理很多情况,所以嵌套的比较深,可以从getObjectForBeanInstancegetObjectFromFactoryBean两个方法入手自己看一下.
    6. 主要的流程就是这样,但是旁支的东西数不胜数,代码远多于这些主线的内容,这里就主线内容说一下.
<think>嗯,用户想了解Spring IOC容器的底层实现原理,特别是源码解析和底层实现机制。首先,我需要回忆一下Spring框架的基本概念。根据提供的引用,SpringIOC容器负责管理对象的依赖关系,用户不再需要手动设置这些依赖,而是从容器中获取对象。引用中提到了BeanFactory和ApplicationContext这两个接口,其中ApplicationContext是更常用的,提供了更多功能。 接下来,用户需要的是源码层面的解析。我需要找出Spring IOC容器的核心流程,比如容器的初始化、Bean的加载和实例化过程。根据引用[4],提到了invokeBeanFactoryPostProcessors和finishBeanFactoryInitialization这两个方法,前者用于处理Bean工厂的后置处理器,后者负责实例化Bean。这可能涉及到BeanFactoryPostProcessor和BeanPostProcessor的区别,需要解释清楚。 然后,Bean的生命周期是关键点。用户可能想知道Spring如何创建和管理Bean,包括实例化、属性填充、初始化等步骤。引用[2]提到doCreateBean方法,虽然未详细分析,但说明这是后续详细分析的部分,所以需要简要说明这个过程。 另外,用户可能对设计模式感兴趣,比如工厂方法模式,引用[5]提到工厂方法模式的定义,Spring中可能使用了这种模式来延迟实例化。需要结合源码中的具体实现,比如DefaultListableBeanFactory的作用。 还需要考虑容器的扩展机制,比如BeanPostProcessor和BeanFactoryPostProcessor的作用,以及如何通过它们扩展容器功能。引用[3]提到BeanFactory是基础接口,ApplicationContext是扩展,可能需要解释两者的区别及在源码中的体现。 最后,生成的相关问题需要涵盖用户可能进一步探索的方向,比如循环依赖的处理、设计模式的应用、Bean生命周期等。确保问题能够引导用户深入理解Spring IOC底层机制。</think>### Spring IOC容器底层实现原理分析 #### 1. 核心架构与接口设计 Spring IOC容器的核心接口是$BeanFactory$和$ApplicationContext$。其中: - $BeanFactory$提供基础容器功能,采用延迟加载策略[^3] - $ApplicationContext$继承$BeanFactory$,添加了国际化、事件传播等企业级特性,其典型实现类$ClassPathXmlApplicationContext$的初始化包含以下关键步骤: ```java public ClassPathXmlApplicationContext(String[] configLocations) { this(configLocations, true, null); } ``` 该构造函数触发容器刷新流程,最终调用$refresh()$方法[^2] #### 2. 容器初始化流程 核心方法$AbstractApplicationContext#refresh()$包含12个关键步骤: ```java public void refresh() { // 1. 准备刷新上下文 prepareRefresh(); // 2. 创建BeanFactory并加载Bean定义 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. 配置BeanFactory prepareBeanFactory(beanFactory); // 4. 执行BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // 5. 注册BeanPostProcessor registerBeanPostProcessors(beanFactory); // 6. 初始化消息源 initMessageSource(); // 7. 初始化事件广播器 initApplicationEventMulticaster(); // 8. 初始化特殊Bean onRefresh(); // 9. 注册事件监听器 registerListeners(); // 10. 完成Bean初始化 finishBeanFactoryInitialization(beanFactory); // 11. 完成刷新 finishRefresh(); } ``` 其中$finishBeanFactoryInitialization()$触发单例Bean的预实例化[^4] #### 3. Bean生命周期管理 关键方法$AbstractAutowireCapableBeanFactory#doCreateBean()$实现Bean的完整生命周期: ```java protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 1. 实例化(反射/CGLIB) BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); // 2. 属性注入(依赖注入) populateBean(beanName, mbd, instanceWrapper); // 3. 初始化(Aware接口/init-method) exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject; } ``` 该过程通过$BeanPostProcessor$实现扩展点(如AOP代理)[^4] #### 4. 依赖注入机制 - 构造器注入:通过$AutowiredAnnotationBeanPostProcessor$处理@Autowired注解 - Setter注入:使用$PropertyValues$封装属性值 - 方法注入:基于CGLIB的动态子类实现 #### 5. 设计模式应用 1. **工厂方法模式**:$BeanFactory$接口定义对象创建规范,具体实现由子类决定[^5] 2. **单例模式**:默认Bean作用域采用单例注册表实现 3. **策略模式**:不同$InstantiationStrategy$处理各种实例化方式 4. **模板方法模式**:$AbstractApplicationContext#refresh()$定义容器刷新流程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值