简述
Bean的生命周期
Spring中所有的bean都是通过反射生成的(constructor->newInstance)。整个过程中还包括很多扩展点,比如两个非常重要的接口BeanFactoryPostProcessor、BeanPostProcessor,用来实现扩展功能,AOP就是在IOC基础上的一个扩展实现,通过BeanPostProcessor实现的。IOC中除了创建对象之后还有一个重要的点就是填充属性。
执行顺序
容器初始化
BeanFactory
FactoryBean
可以不遵守Bean的生命周期,自定义Bean的创建过程。
- isSingleton判断是否为单例对象
- getObjectType获取对象的类型
- getObject在此方法中可以自己创建对象,使用new或者代理的方式都可以,用户可以按照自己的需要随意去创建。
很多框架继承的时候都会实现FactoryBean,比如Feign
加载Bean定义
通过读取配置加载Bean定义为BeanDefinition对象,然后将所有BeanDefinition的名字创建一个集合,通过遍历beanNames集合进行Bean的实例化。
实例化 Instantiation
通过createBeanInstance方法反射实例化Bean对象,此时的Bean对象只是创建了,而Bean对象的属性均未进行赋值(都是默认值),例如A对象依赖注入了B对象,那么此时A实例中的B对象是空的。
属性赋值 Populate
当Bean对象创建后属性都是默认值,通过populateBean方法来完成对象的属性赋值。在这过程中会出现循环依赖的问题(A->B,B->A),Spring通过三级缓存策略解决。
循环依赖问题
当A依赖B、B依赖A形成循环依赖,通过三级缓存解决循环依赖问题。
当创建A时,先实例化A,A当中的属性B需要赋值,发现B没有创建,出实例化B,发现B中的属性A需要赋值,而A又在创建中。
此时使用二级缓存来解决问题,一级缓存放成品对象,二级缓存放半成品对象(只实例化了没给属性赋值)。
当程序使用到了AOP,必须依赖三级缓存。三级缓存的value类型是ObjectFactory,是一个函数式接口,不是直接调用的,只有在调用getObject方法的时候才会去调用里面存储的lamabda表达式,保证整个容器的运行过程中同名的bean对象只有一个。一级缓存 singletonObjects
用于保存BeanName和创建bean实例之间的关系 Cache of singleton objects: bean name to bean instance.- 二级缓存 earlySingletonObjects
保存BeanName和创建bean实例之间的关系,与singletonFactories的不同之处在于,当一个单例bean被放到这里之后,那么当bean还在创建过程中 就可以通过getBean方法获取到,可以方便进行循环依赖的检测 Cache of early singleton objects: bean name to bean instance. 三级缓存 singletonFactories
三级缓存 用于保存BeanName和创建bean的工厂之间的关系 Cache of singleton factories: bean name to ObjectFactory.初始化Initialization
当所有非懒加载的Bean对象都实例化并属性赋值完成后,还需要对这些Bean对象进行初始化方法回调。
向bean对象中设置容器属性,会调用invokeAwareMethods方法来将容器对象设置到具体的Bean对象中。
- 调用BeanPostProcessor中的前置处理方法来进行bean对象的扩展工作,ApplicationContextPostProcessor、EmbeddValueResolver等对象
- 调用InvokeInitMethods方法来完成初始化方法的调用,在此方法处理过程中,需要判断当前bean对象是否实现了InitializeingBean接口,如果实现了则调用afterPropertiesSet方法来最后设置bean对象
- 调用BeanPostProcessor的后置处理方法,完成对Bean对象的后置处理工作,aop就是在此处实现的,实现的接口名叫AbstractAutoProxyCreator
获取到完整对象,通过getBean的方式去进行对象的获取和使用
销毁Destruction
当对象使用完成之后,容器在关闭的时候会销毁对象,首先判断是否实现了DispoableBean接口,然后去调用destroyMethod方法
IOC控制反转
把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的需求,但是高层并不用管底层是怎么实现的。
DI依赖注入
DI指依赖注入,将对应的属性注入到具体的对象中。原来我们使用对象需要使用者主动创建。有了Spring之后,可以将整个对象交给容器来帮我们进行管理。
通过@Autowire、@Resource注解和populateBean方法来完成注入:@Autowired默认是byType,根据对象类型进行注入Bean。
- @Resource 默认byName,可通过设置name或type属性来进行注入Bean。
- populateBean方法为bean对象注入属性。
AOP面向切面编程
面向切面编程是一种思想,它将应用程序看做一个面,并通过切面把程序看做多个层级,通过切面对程序进行横向扩展。AOP(spring-aspects)是Spring提供的面向切面编程实现方式。AOP通过IOC预留的扩展点实现(BeanPostProcessor)。切面执行顺序
代理模式
AOP通过代理模式实现,实现代理模式有静态代理和动态代理两种,而AOP采用的是动态代理。
- 静态代理:指编写的代码符合代理模式,这种代理模式依赖于硬编码,不够灵活。
动态代理:AOP采用动态代理。动态代理指不依赖于硬编码,程序通过反射机制动态生成代理类。
动态代理实现
动态代理又有两种实现方式,一个是JDK官方提供的,一个是cglib提供的。
JDK动态代理:通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
- CGLIB动态代理:如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
Spring事务
通过动态代理实现,@Configuration、@Transactional注解开启。