spring底层

bean的加载

L4dAr8.png

xml->获取io流->解析xml->获取document->获取斧子节点->设置到beandefinition中

L40DED.png

beanFactory

如果要访问容器的话必须要经过beanFactory

常用的ApplicationContext就继承自BeanFactory(BeanFactory为根接口)

L4D9w8.png

BeanFactoryPostProcessor其中有个子类在解析xml时会去替换占位符

L4sdRH.png

bean的生命周期

  1. 实例化:在内存中开辟空间
  2. 初始化:属性赋值
  3. 使用对象
  4. 销毁对象

bean会保存到一个map中去

DefaultSingletonBeanRegistry中有几个map

private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//一级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);//三级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap(16);//二级缓存

实例化

在堆中申请内存,属性值默认值

调用createBeanInstance

反射

  1. class对象
  2. 构造器
  3. new Instance

L4cRJO.png

设置(自定义)属性

这个属性是设置自定义属性

populateBean调用set方法赋值

调用aware相关接口

调用aware相关接口,设置相关依赖

这个属性是设置容器属性

invokeAwareMEthods

Aware是检查当前接口是否为容器接口的

初始化

执行前置后置处理方法

BeanPostProcessor有俩个方法postProcessBeforeInitialization和postProcessAfterInitialization

AOP用动态代理去初始化类

默认后置进行了AOP 动态代理 1,jdk动态代理, 2cglib动态代理

前置默认无操作

postProcessBeforeInitialization->invokeInitMethods->后置 postProcessAfterInitialization

invokeInitMethods

判断bean是否实现了InitializingBean接口,如果实现了调用afterPropertiesSet

中间的为调用初始化方法

在配置bean时会指定init-method

把对象交给容器管理

调用getSingleton方法,调用了addSingleton,(sync方法)

将映射关系添加到一级缓存中

容器就可以进行管理起来了

销毁

很少使用context.clase()销毁对象,一般很少使用

beanFactory和factoryBean的区别

benaFactory:

必须遵循完整的bean的生命周期去创建对象

较为复杂,流水线式的创建对象

BeanFactory 是底层的Ioc容器,ApplicationContext 继承了它,并增加了一些特性。在实现方面,ApplicationContext 组合了一个 BeanFactory 的实现,使用这个实现对象来完成一些操作。

factoryBean

FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式(如果想了解装饰模式参考:修饰者模式(装饰者模式,Decoration)我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类.

创建对象,没有标准的流程,私人订制,用自己的方式去创建对象

方法

isSingleton:判断是否是单例

getObjectType:返回对象的类型

getObject:返回对象

循环依赖

逻辑

spring的默认对象是单例的

比如A与B俩个对象是循环依赖的

一般如图所示

对象分为俩种

成品对象:完成实例化且完成初始化

半成品:完成实例化

在b判断容器中是否有a对象时

三级缓存解决循环依赖

解决思路:在实例化对象之后放入一个map中,一个map放半成品,一个map放成品对象

当需要创建对象的时候先去半成品的map中取,去半成品map中进行赋值,赋值完成变为成品对象后继续初始化

源码中的定义

private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//一级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);//三级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap(16);//二级缓存

一级和二级缓存是concurrentHashMap,三级HashMap

他们的初始容量也不一样

一级二级放的是Object三级中放的是ObjectFactory

ObjectFactory定义

@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}

ObjectFactory是一个函数式接口,有且仅有一个方法,可以当做方法的参数传递进去,当指名此类型参数的方法,可以传入一个lambda表达式,在执行的时候并不会执行lambda表达式,在调用getObject()方法的时候才会去调用lambda的处理逻辑

调用逻辑

  1. getBean:先判断容器里是否有对象,之后进行getBean
  2. doGetBean:实际获取bean的方法,在其中会用getSingleton获取对象判断缓存中是否有注册单例的对象
  3. createBean:执行getSingleton,传入lambda表达式(不会立刻执行)
  4. doCreateBean:实际创建bean对象的逻辑
  5. createBeanInstance创建bean实例(到这里完成了实例化a对象)
    之后将会执行addSingletonFactory,方法向三级缓存中put包含当前对象的lambda表达式,然后清空2级缓存

(最后将beanNAme添加已注册的单例集合中,和三级缓存无关)

  1. populateBean:填充属性,如果没有获取到属性对象,就去容器中获取,先去一级缓存中获取,获取不到的话,去二级获取不到去三级获取(getObject).如果在三级缓存中没有,就去创建对象重走逻辑.如果在三级缓存中取到了,就返回经过层次包装后的对象,然后将当前创建的对象放入二级缓存中,删除原来三级缓存中的b(在二级缓存中的对象依旧是半成品,删除三级缓存是因为,二级缓存有了就不会查找三级缓存了).对象整个创建完毕变为成品对象后,会移除二级三级缓存,放入到一级缓存之中

比如AB存在循环引用

先创建A对象->判断是否有注册->初始化->放入三级缓存->注入属性(B对象)->获取去三级缓存中获取b对象->为获取到->创建b对象->初始化->放入三级缓存->注入属性(A对象)->去获取三级缓存中的A对象(经过层次包装后的对象)->成功获取到A对象->将A对象放到二级缓存中(此时A依旧是半成品)->清除三级缓存(二级缓存有了就不会查询三级缓存了)->B对象变为成品对象->b对象放入一级缓存中->获取到b对象->给A对象中的b属性赋值->将A放入一级缓存->删除二级缓存->在一级缓存中获取到B对象,并给A设置

总结

三个map结构分别存储什么对象

一级缓存:成品

二级缓存:办成品

三级缓存lambda表达式

查找顺序

依次从一级缓存到三级缓存

思考

如果只有俩个map能否解决循环依赖的问题?

能但有前提条件,循环依赖中不包含aop的处理逻辑

为什么三级缓存可以解决循环依赖中包含的代理对象的问题?

  1. 创建代理对象的时候是否需要创建出原始对象?

    • 需要
  2. 同一个容器中,能否出现同名的俩个不同对象

    • 不能
  3. 如果一个对象被代理,那么代理对象和原始对象该如何进行存储

    • 如果需要代理对象,那么代理对象创建完成之后应该覆盖原始对象
      在getEarlyBeanReference方法中会判断是否需要代理对象,如果创建出代理对象了,那么就需要覆盖
  4. 在对象对外暴露了的时候,如何准确的给出原始对象或者代理对象,(因为正常代理对象的创建是BeanPostProcessor的后置处理方法中,在解决循环依赖的问题的时候还没执行到那个地方)

    • 此时需要lambda表达式了,类似于一种回调机制,在确定要对外暴露的时候,就唯一性的确定到底是代理对象还是原始对象,这也是为什么不把对象直接放到二级缓存中,而是通过三级缓存lambda表达式的方式来执行原因

简单来说什么时候需要对外暴露,程序没办法确定,而lambda表达式在被调用时才会去执行,确定返回的是代理对象还是原始对象

为什么spring提供了一个循环依赖的解决机制,但是业务中还会遇到循环依赖问题呢?

spring是一个跟业务无关的技术框架,只能预防一些问题,而不是解决所有问题

spring中的设计模式

  1. 单例模式:spring中的bean默认都是单例
  2. 工厂模式:BeanFacotry
  3. 模板方法:postProcessorBeanFactory,onRefresh(留给扩展子类来进行实现的)
  4. 观察者模式:Wlistener,event,multicast
  5. 适配器模式Adapter
  6. 装饰器模式BeanWrapper
  7. 责任链模式:使用aop的时候会有一个链式责任
  8. 代理模式:aop动态代理
  9. 委托者模式:delegate
  10. 建造者模式:builder
  11. 策略模式:XmlBeanDefinittionReader,PropertiesBeanDefinitionReader
Last modification:April 26, 2022
如果觉得我的文章对你有用,请随意赞赏