Spring——IoC

作者: Lnstark | 来源:发表于2021-10-24 23:00 被阅读0次

BeanDefinition

BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载、依赖的bean、创建该bean的工厂等,它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean。

FactoryBean

FactoryBean接口有getObject、getObjectType和isSingleton三个方法,实现了此接口的bean容器会注入getObject方法返回的对象。如果要拿FactoryBean对象,就在bean的name前加个"&"。

bean的创建过程

  1. BeanDefinitionParser通过解析加载xml配置文件、解析等方式读取BeanDefinition(BD),将它们注册到BD注册中心
  2. 执行BeanFactoryPostProcessorpostProcessBeanFactory方法。该方法可以对BeanFactory做很多事,例如对BD注册中心里的BD进行增删改等。
  3. 加载BD里的BeanPostProcessors
  4. 执行BeanPostProcessor(具体实现是InstantiationAwareBeanPostProcessor. postProcessBeforeInstantiation());
  5. 选取合适的构造方法,通过反射实例化bean。
  6. 执行执行BeanPostProcessor(具体实现是InstantiationAwareBeanPostProcessor. postProcessAfterInstantiation());
  7. bean初始化,对bean进行属性填充(populateBean方法里)。放入spring缓存。
  8. 如果bean实现了Aware接口(BeanNameAwareBeanClassLoaderAwareBeanFactoryAware),那么执行对应的set方法。然后执行BeanPostProcessor.postProcessBeforeInitialization()方法
  9. 如果bean实现了InitializingBean接口,那么执行afterPropertiesSet方法。然后执行自定义初始化方法。
  10. 执行BeanPostProcessor.postProcessAfterInitialization()方法。

其中6-7是在populateBean()方法里。8-9是在initializeBean()方法里。bean的生命周期从5开始,10之后bean可以使用,在容器销毁之后如果bean实现了DisposableBean方法,那么调用他的destroy方法。然后调用自定义销毁方法。

循环依赖及其解决方法

什么是Spring循环依赖

bean创建过程中出现A依赖B,然后B又依赖A,或者A依赖B,B依赖C,C依赖A的情况就是循环依赖。
spring无法解决原型模式bean的循环依赖,也无法解决单例bean的构造方法参数造成的循环依赖。它只能解决单例bean的setter造成的循环依赖。

解决方式

三级缓存
// 一级缓存
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 ConcurrentHashMap<>(16);
解决流程

假设A依赖B,B依赖A,先创建A。

  1. 执行doGetBean拿A,先从缓存里找A,肯定无
  2. 实例化A,然后放进3级缓存
  3. 对A进行属性注入,发现依赖了B
  4. doGetBean B,同样步骤,直到创建完B,存到3级缓存,再对B进行属性注入,发现依赖了A
  5. 去缓存里找A,拿到了,并把A从3级缓存升到2级
  6. 拿到A的B继续走流程,直到创建完,就加入到1级缓存,清掉2、3级缓存里的B
  7. 回到A的流程,直到创建完,就加入到1级缓存,清掉2、3级缓存里的A
那为啥构造器模式下循环依赖不能解决呢?

假如A的构造方法里有B,在创建A前,A的beanName会加入到singletonsCurrentlyInCreation的Set里。在实例化A时,回去找B,然后去创建B。创建B时又发现依赖了A,又去找A,但是跟上面不一样的是,这时候缓存里没有A,spring判断了A还在singletonsCurrentlyInCreation的Set里,于是抛了个异常。
而反过来,A如果是setter方法里依赖B,B是构造方法里依赖A的话,流程是没有问题的。因为在实例化B时,B去找缓存里的A是可以找到的。所以A在setter里依赖B,而B在构造方法里依赖A的情况下是可以解决的。

为啥要用三个缓存而不是两个?

如果一个对象被AOP注解了,那他在三级缓存里的ObjectFactory.getObject操作是会进行代理,如果只用2个缓存(1级和3级),那每次执行ObjectFactory.getObject都会被代理,显然不合理。所以在执行一次之后,就把他升级到二级缓存了。

相关文章

网友评论

    本文标题:Spring——IoC

    本文链接:https://www.haomeiwen.com/subject/xwitaltx.html