目录
6. BeanFactory和ApplicationContext的区别
1. 聊一下IOC的理解
1.1 什么是IOC,IOC就是控制反转,spring之前开发过程中我们要使用对象都是自己new出来然后进行赋值初始化一系列操作,包括使用完成之后的销毁,都由开发自己控制,spring出现以后,对象的创建、初始化及销毁的过程都交给容器帮我们进行管理,这是IOC的理论思想。
1.2 谈到IOC顺带说一下DI依赖注入,将对应的属性注入到具体的对象中,平时我们在项目中一般是通过@Autowired,@Resource注解来进行注入的。当我们在实际调用的时候,属性的注入还会通过populateBean方法来完成。
1.3 容器:使用map结构来存储对象,在Spring存储对象的时候一般有三级缓存。singletonObjects存放已完成初始化,属性已赋值的完整对象。earlySingletonObjects存放已实例化,属性还未赋值的半成品对象,singletonFactory用来存放创建单例bean的工厂。整个bean的生命周期(从创建到销毁)都是由容器来帮我们控制的。
在IOC体系中还有很多细节的点,我源码是之前看的,而且只看过一遍,记不太清了。Spring中所有的bean都是通过反射的方式创建的,先调用getConstructor()方法获得默认的构造器,再通过调用构造器的newInstance()方法生成bean。在整个流程中还会包含很多扩展点,比如有两个非常重要的接口:BeanFactoryPostProcessor和BeanPostProcessor,用来实现扩展功能,AOP就是通过BeanPostProcessor实现的。
2. 容器的创建过程
容器有refresh()方法进行创建,里面分为12个大的步骤,分别如下:
转载:spring容器创建过程(总结版)_大叶子不小的博客-优快云博客
3. bean的生命周期
- 实例化bean对象,通过反射方式来生成,源码中有一个createBeanInstance()方法是专门用来生成对象的。
- bean实例化后调用populateBean()方法来填充对象的属性,这里面会利用三级缓存来解决循环依赖问题。
- 调用invokeAwareMethod()方法,检查是否实现aware接口
- 如果Bean实现了BeanNameAware接口的话,调用setBeanName()方法设置BeanName
- 如果Bean实现了BeanFactoryAware接口的话,调用setBeanFactory()方法,设置BeanFactory
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。使用比较多的有(ApplicationContextPostProcessor,设置Application, Environment, ResourceLoader, EmbedValurResolver等对象)
- 调用invokeInitMethods方法来完成初始化方法的调用,如果bean对象实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。
- 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法完成bean对象的后置处理工作,AOP就是在此处实现的,实现的类为AbstractAutoProxyCreator。
- 此时,Bean已经准备就绪,通过getBean()方法来获取到具体的对象。
- 销毁流程,1、判断是否实现了DisposableBean接口,2、调用destroyMethod方法。
4. BeanFactory和FactoryBean的区别
BeanFactory和FactoryBean都可以用来创建对象,只不过创建的流程和方式不同,当使用 BeanFactory的时候,必须要严格的遵守bean的生命周期,经过一系列繁杂的步骤之后才可以创建出单利对象,是流水线式的创建过程。
而FactoryBean是用户可以自定义bean对象的创建流程,不需要按照bean的生命周期来创建,在此接口中包含了三个方法:
1) isSingleton-是否单例。
2) getObjectType-获取对象的类型。
3) getObject:在此方法中创建对象,new()、反射、动态代理的方式都可以。
很多框架集成的时候都会实现FactoryBean接口,比如Feign。
5. Spring中用到哪些设计模式
1)单例模式:spring默认所有的bean都是单例的。
2)原型模式:指定scope="prototype"。
3)工厂模式:BeanFactory。
4)模板方法:postProcessBeanFactory, onRefresh, initPropertyValue
5)观察者模式:listener,event,multicast
6)适配器模式:Adapter
7)装饰者模式:BeanWrapper
8)责任链模式:使用aop的时候会一个调用方法getInterceptorsAndDynamicInterceptionAdvice()
9)代理模式:aop动态代理
10)建造者模式:builder
...
6. BeanFactory和ApplicationContext的区别
BeanFactory是访问spring容器的根接口,里面只是提供了某些基本方法的约束和规范,为了满足更多的要求,ApplicationContext实现了该接口,并在此接口的基础上做了某些扩展功能,提供了更加丰富的api调用。一般我们在使用的时候用ApplicationContext更多。
7. Spring是如何解决循环依赖问题的
什么是循环依赖?如下图:
解决办法:Spring中bean对象的创建都会经历实例化和初始化(属性填充)两个步骤,通过区分对象的状态,就是半成品状态(未完成属性的填充,但是已有引用)和成品状态(完成了属性的填充)。成品对象存入一级缓存,半成品对象存入二级缓存。三级缓存的value类型为ObjectFactory,这个后面细说。
通过区分不同的状态就能打破前面所描述的循环依赖问题了,当实例化A对象的时候,b属性未完成赋值,此时A对象就是一个半成品对象,这时候将半成品对象A放入二级缓存中,当给B对象中的a属性赋值的时候,优先从一级缓存中找,没找到再去二级缓存中找,这个时候就能找到并成功赋值,这样就打破了循环。
只有一级缓存是不够的,因为这样会把成品状态的bean和半成品状态的bean放在一起,而半成品对象是不能暴露给外部进行使用的。
只有二级缓存也是不够的,因为会涉及到AOP动态代理,代理对象在生成之前一定会先生成一个原始对象,当代理对象生成以后就会同时存在代理对象和原始对象,此时就需要判断我们到底该使用哪一个对象,当需要使用代理对象时,就必须要覆盖掉原始对象,也就是说,整个容器中不会出现两个同名的bean对象。
在实际调用的过程中,是没有办法来确定对象什么时候被使用,因此当某一个对象被调用的时候,优先判断当前对象是否需要被代理,类似回调机制,当获取对象之后根据传入的lambda表达式来确定返回的是原始对象还是代理对象,利用getEarlyBeanReference()方法来处理。