IOC
IOC的定义及Spring中的实现方式
IOC的中文解释为控制反转,是面向对象编程中的一种设计原则,用来降低代码之间的耦合度。个人理解就是将控制权反转,在耦合度较高的情况下,将对象的创建交给别人来做,而自身知道这个东西,当有需要的时候直接告知对方,对方将操作进行实现。从而降低两者的耦合度
Spring中的IOC实现为DI(依赖注入),Spring中的依赖注入分为构造器注入和Set注入。
依赖注入的发生时机
依赖注入在以下两种情况发生:
1.对应 Bean 对象未配置成懒加载的方式即 @Lazy(value = false) 或未使用该注解,则会在初始化 IOC 容器(Bean Factory)完成之后对非懒加载 BeanDefinition 进行实例化和依赖注入。
2.懒加载 Bean 对象在用户第一次调用 getBean()方法时,IOC 容器触发 Bean 的实例化和依赖注入。
依赖注入和Bean的加载
依赖注入和Bean的加载发生在不同时期,依赖注入需要前期Bean的加载完成,并且IOC初始化时才会进行。Bean的加载涉及到Spring容器对XML配置文件的解析过程。
循环依赖
在Bean加载的过程中会发生一种情况,A依赖于B,B又依赖于A,此时,A实例化中,发现依赖B,于是前去实例化B,在B的实例化过程中,发现要实例化A,此时陷入一种死循环中,这就是循环依赖的发生场景。
Spring为了解决这个问题,采用了一个半成品形式的实例化过程,先创建一个原始对象,不设置属性,当A实例化时发现依赖了B,此时先去实例化B,B实例化时发现依赖A,此时将A的半成品放入B中,B实例化完成,A相应的也可以继续实例化。为了解决这个问题,Spring设计了三级缓存。三级缓存分别是:
singletonObjects:完成初始化的单例对象的cache,这里的bean经历了实例化->属性填充->初始化以及各种后置处理
earlySingletonObjects:存放原始的bean对象(完成实例化但是尚未填充属性和初始化),仅仅能作为指针提前曝光,被其他bean所引用,用于解决循环依赖
singletonFactories:在bean实例化完之后,属性填充以及实例化之前,如果允许提前曝光,Spring会将实例化后的bean提前曝光,也就是把该bean转换成beanFactory并加入到singletonFactories
Bean创建在三级缓存中的流程(单例模式下)
单例bean在实例化后都会被提前曝光到三级缓存中,不存在循环依赖的实例会在后续的操作完成后,直接放入一级缓存中,存在循环依赖的实例,Spring会将半成品的实例化引用放入二级缓存中,随后对该实例进行后续操作,放入一级缓存。
三级缓存的设计据说涉及到了AOP代理的问题,后续在参考各方的讲解后进行更新。
AOP
AOP的中文解释为面向切面编程,旨在对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低。(相较IOC两者的降耦方面不一样),整体的实现结果就是通过预编译方式和运行其动态代理实现在不修改源代码的情况下给程序动态同一添加某种特定功能的一种技术。
Spring中的AOP
Spring中的AOP使用JDK动态代理或者CGLIB来为目标对象创建代理。(尽量使用JDK动态代理),如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理,所有该目标类型实现的接口都将被代理,若该目标对象没有实现任何接口,则创建一个CGLIB代理。使用CGLIB代理将无法通知final方法,因为他们不能被覆写,同时需要将CGLIB二进制发行包放在classpath下面。