• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

谈谈你对Spring IOC的理解【建议收藏】

互联网 diligentman 2小时前 2次浏览

背诵并默写:

        SpringIOC有两个核心思想就是IOC控制反转和DI依赖注入,IOC 控制反转的基本思想是,将原来的对象控制从使用者,有了spring之后可以把整个对象交给spring来帮我们进行管理,DI 依赖注入,就是把对应的属性的值注入到具体的对象中。spring提供<bean/>标签和@Autowired和@Resource注解等方式注入,注入方式本质上是AbstractAutowireCapableBeanFactory的populateBean() 方法先从beanDefinition 中取得设置的property值,例如autowireByName方法会根据bean的名字注入;autowireByType方法根据bean的类型注入,完成属性值的注入(涉及bean初始化过程)。对象会存储在map结构中,在spring使用Map结构的singletonObjects存放完整的bean对象(涉及三级缓存和循环依赖)。整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理(涉及bean的生命周期)

扩展,如果面试官不叫停可以继续说(*bean生命周期

        IOC核心流程重点关注有 bean生命周期,主要分为初始化和销毁
1、在正式进入容器的刷新前,会进行一些前置操作。主要为了(1)确认要使用的容器,通常使用的是:XmlWebApplicationContext,如果是用 Spring Boot,一般是AnnotationConfigApplicationContext,但其实都差别不大,最终都会继承AbstractApplicationContext,核心逻辑也都是在 AbstractApplicationContext 中实现。(2)还有一个目的是提供一个给开发者初始化 ApplicationContext 的机会。
————————————初始化过程————————————

2、初始化 BeanFactory默认为 DefaultListableBeanFactory 、它会加载 Bean 定义,向bean工厂中设置一些参数;例如:BeanNameAware.setBeanName() 在创建此bean的bean工厂中设置bean的名称和BeanClassLoaderAware.setBeanClassLoader()setBeanFactory() : 回调提供了自己的bean实例工厂等,然后将 beanName、BeanDefinition 放到 BeanFactory 的缓存中,用于后续创建 Bean 实例时使用。

3、触发 BeanFactoryPostProcessor;BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IOC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级;另外,Mybatis 中的 MapperScannerConfigurer 是一个典型的 BeanDefinitionRegistryPostProcessor 的扩展使用;

我们也可以implements BeanFactoryPostProcessor 再使用@Component注册到Spring,实现自己的 postProcessBeanFactory() 逻辑。

4、注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,方便后续对bean对象完成具体的扩展功能;

我们也可以implements BeanPostProcessor再使用@Component注册到Spring,实现自己的postProcessBeforeInitialization()和postProcessAfterInitialization()

5、实例化所有剩余的非懒加载单例 bean,将所有BeanDefinition对象实例化成具体的bean对象。(1)首先会遍历所有被加载到缓存中的 beanName,触发所有剩余的非懒加载单例 bean 的实例化。(2)同时通过 beanName 尝试从缓存中获取,如果存在则跳过实例化过程;否则,进行 bean 的实例化。(3)根据 BeanDefinition使用构造函数创建 bean 实例 或者 进行 bean 实例属性填充。最后执行 bean 实例的初始化。

6、生成完整的bean对象,通过getBean方法可以直接获取。

————————————销毁————————————

7、在BeanFactory 关闭的时候,Bean的生命周期会调用如下方法:(1)DestructionAwareBeanPostProcessor.postProcessBeforeDestruction(): 在销毁之前将此BeanPostProcessor 应用于给定的bean实例。能够调用自定义回调,像是DisposableBean 的销毁和自定义销毁方法,这个回调仅仅适用于工厂中的单例bean(包括内部bean)(2)实现了自定义的 destory() 方法

扩展,还不叫停继续说(*重点关注的类

        这里面主要关注对象有,bean 是一个由Spring IOC容器实例化,组装和管理的对象;
BeanDefinition 是bean的定义,用来存储bean的所有属性方法定义。ApplicationContext BeanFactory  的子接口,在 BeanFactory 的基础上构建,是相对比较高级的IOC容器实现。包含 BeanFactory 的所有功能,还提供了其他高级的特性,比如:事件发布、国际化信息支持、统一资源加载策略等。正常情况下,我们都是使用的 ApplicationContext。还有BeanFactory是基础类型 IOC 容器,提供完整的 IOC 服务支持。FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法即可。

结尾

        面试官,这是我对Spring IOC的整体理解,包含了一些详细的处理过程,您看一下有什么问题,可以指点我一下(心里想看老子不吊打你)

———————————等等面试官还没叫停?—————————————

扩展,还不叫停石锤面试官睡着了,那我们展开继续说(*bean的初始化过程中循环依赖和解决)

刚才说,对象会存储在map结构中,在Spring使用Map结构的singletonObjects存放完整的bean对象。

但是创建这个singletonObjects的过程。Spring在启动的时候会先初始化扫描我们配置的包下面的所有的类,进行解析和注册到beanDecfinition中。然后在根据beanDecfinition的信息对类进行实例化,填充属性等操作变成一个bean,放到我们spring的容器中。在变成bean的过程中,会遇到对象与对象之间的依赖,比如A类中有一个属性B类,那么spring在创建A对象的时候发现了需要一个B对象,这个时候spring就会暂时停止对A的创建,会先去创建B对象,等B对象创建完之后,将B对象注入到A对象中,再接着创建A对象剩下的工作。

这个过程我们分为两部分,首先1、通过反射创建出一个对象,然后2、往对象中的属性赋值。

我们很好理解第一步,我们得到对象的全路径名,就可以利用反射创建A对象,得到A对象中的属性。这时我们会把这个A对象标为正在创建中,并且放到缓存中。

在第二步时就要给属性赋值,这时如果属性中要注入B类的话,spring会首先到容器中找有没有B类的对象,有的话就直接注入在属性上。没有的话就就要重新创建一个B对象,在创建B对象的过程中,必然也会有两步:1、通过反射创建出一个对象,2、往对象中的属性赋值。第一步和之前一样我们不说,第二步的就有可能会注入我们之前正在创建的A对象,同样也到容器中查找,没有找到,因为我们还没有创建完成,这个时候我们会发现他正在创建中,然后我们可以从缓存中取出创建好但没有注入属性值的A对象,然后就去拿着这个A对象给当前B对象注入值。这样就完成了当前B对象的注入。B对象创建完成之后,就会把B对象注入到A中,A对象就创建完成了。

谈谈你对Spring IOC的理解【建议收藏】

end


程序员灯塔
转载请注明原文链接:谈谈你对Spring IOC的理解【建议收藏】
喜欢 (0)