栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码解析-三级缓存与循环依赖

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码解析-三级缓存与循环依赖

// 如果两个条件满足,说明出现了循环依赖

if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {

synchronized (this.singletonObjects) {

// 再从二级缓存中获取

singletonObject = this.earlySingletonObjects.get(beanName);

// 这里又有两个判断

// singletonObject == null 表示在二级缓存中没有获取到

// allowEarlyReference 这个值传进来就为true,表示是否允许获取早期引用

// 如果两个条件都满足,就到三级缓存中获取

if (singletonObject == null && allowEarlyReference) {

// 从三级缓存获取,注意,这里获取到是一个ObjectFactory

ObjectFactory singletonFactory = this.singletonFactories.get(beanName);

if (singletonFactory != null) {

// 通过ObjectFactory获取bean实例

singletonObject = singletonFactory.getObject();

// 打怪升级,从三级缓存升级到二级缓存,

this.earlySingletonObjects.put(beanName, singletonObject);

this.singletonFactories.remove(beanName);

}

}

}

}

// 返回bean

return singletonObject;

}

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {

Assert.notNull(beanName, “Bean name must not 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 be null”);

synchronized (this.singletonObjects) {

// 从一级缓存中获取bean

Object singletonObject = this.singletonObjects.get(beanName);

// 如果bean为空

if (singletonObject == null) {

if (this.singletonsCurrentlyInDestruction) {

throw new BeanCreationNotAllowedException(beanName,

"Singleton bean creation not allowed while singletons of this factory are in destruction " +

“(Do not request a bean from a BeanFactory in a destroy method implementation!)”);

}

if (logger.isDebugEnabled()) {

logger.debug(“Creating shared instance of singleton bean '” + beanName + “'”);

}

// 单例bean创建前会将这个bean放到一个容器中,标志这个bean正在创建中

beforeSingletonCreation(beanName);

boolean newSingleton = false;

boolean recordSuppressedExceptions = (this.suppressedExceptions == null);

if (recordSuppressedExceptions) {

this.suppressedExceptions = new LinkedHashSet<>();

}

try {

// 执行匿名内部类方法

singletonObject = singletonFactory.getObject();

newSingleton = true;

}

catch (IllegalStateException ex) {

singletonObject = this.singletonObjects.get(beanName);

if (singletonObject == null) {

throw ex;

}

}

catch (BeanCreationException ex) {

if (recordSuppressedExceptions) {

for (Exception suppressedException : this.suppressedExceptions) {

ex.addRelatedCause(suppressedException);

}

}

throw ex;

}

finally {

if (recordSuppressedExceptions) {

this.suppressedExceptions = null;

}

// 单例bean创建完成后,会把bean从这个容器中移除

afterSingletonCreation(beanName);

}

// newSingleton为true时,表示bean创建成功

if (newSingleton) {

// 把bean放到一级缓存中,一级缓存就是我们常说的IOC容器

addSingleton(beanName, singletonObject);

}

}

return singletonObject;

}

}

protected void addSingleton(String beanName, Object singletonObject) {

synchronized (this.singletonObjects) {

// 放进一级缓存中

this.singletonObjects.put(beanName, singletonObject);

// 从三级缓存中移除

this.singletonFactories.remove(beanName);

// 从二级缓存中移除

this.earlySingletonObjects.remove(beanName);

this.registeredSingletons.add(beanName);

}

}

从上面的代码我们已经可以总结出bean没有出现循环依赖时,流程是怎么样的?

  1. getSingleton()方法查看是否存在于一级缓存中,是则获取,无则走下面的创建流程,因为没有出现循环依赖,isSingletonCurrentlyInCreation(beanName),此判断是false

  2. createBean()方法创建一个bean

  3. addSingleton()方法将bean放到一级缓存中

当然,在正常的流程中会穿插异常流程的处理方式,比如bean创建前会把bean放到一个容器中,Spring凭借这个可以知道bean是否正在创建中,得知bean在创建中后,会利用三级缓存获得bean空壳

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

throws BeanCreationException {

// mbd.isSingleton():bean是否是单例

// this.allowCircularReferences:是否允许出现循环依赖

// isSingletonCurrentlyInCreation(beanName):bean是否在创建中

// 如果三个条件都满足,说明出现了循环依赖

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

isSingletonCurrentlyInCreation(beanName));

if (earlySingletonExposure) {

if (logger.isTraceEnabled()) {

logger.trace(“Eagerly caching bean '” + beanName +

“’ to allow for resolving potential circular references”);

}

// 将bean放到三级缓存中

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

}

// Initialize the bean instance.

Object exposedObject = bean;

try {

// 属性赋值

populateBean(beanName, mbd, instanceWrapper);

// bean初始化

exposedObject = initializeBean(beanName, exposedObject, mbd);

}

catch (Throwable ex) {

if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {

throw (BeanCreationException) ex;

}

else {

throw new BeanCreationException(

mbd.getResourceDescription(), beanName, “Initialization of bean failed”, ex);

}

}

// 如果出现了循环依赖

if (earlySingletonExposure) {

// 从各级缓存中获取bean,getSingleton(beanName, false)这个方法是不是很熟悉,上面已经使用到了

// 只是第二个参数从true变成了false,这个参数决定了要不要从第三级缓存中获取数据

// 代码走到这个地方,已经无需获取早期引用了,所以参数为false

Object earlySingletonReference = getSingleton(beanName, false);

// 如果二级缓存不为空

if (earlySingletonReference != null) {

// 并且二级缓存中的bean跟exposedObject相等,说明初始化时,没有使用代理修改bean对象

if (exposedObject == bean) {

// 直接将二级缓存中bean返回即可

exposedObject = earlySingletonReference;

}

return exposedObject;

}

我们重点看看addSingletonFactory()这个方法,我们先看一段简单代码,感受一下ObjectFactory这个类的作用

public class ObjectFactoryTest {

public static void main(String[] args) {

HashMap> map = new HashMap<>(2);

map.put(“a”, () -> {

System.out.println(“objectFactory”);

return “string”;

});

System.out.println(map.get(“a”).getObject());

}

}

原来,ObjectFactory可以定制执行方法,那么Spring要定制的执行方法是什么?

protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {

Assert.notNull(singletonFactory, “Singleton factory must not be null”);

synchronized (this.singletonObjects) {

if (!this.singletonObjects.containsKey(beanName)) {

// 放入三级缓存

this.singletonFactories.put(beanName, singletonFactory);

this.earlySingletonObjects.remove(beanName);

this.registeredSingletons.add(beanName);

}

}

}

// 要定制的执行方法就是一个beanPostProcess的埋点

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {

Object exposedObject = bean;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {

SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;

exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);

}

}

}

return exposedObject;

}

// AOP的beanPostProcess重写了这个方法

@Override

public Object getEarlyBeanReference(Object bean, String beanName) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

this.earlyProxyReferences.put(cacheKey, bean);

return wrapIfNecessary(bean, beanName, cacheKey);

}

原来,要定制执行方法的原因是,bean的初始化的过程中,AOP动态代理有可能对这个bean进行增强,增强后的bean就是一个代理类,不是原来的类,循环依赖时,我们要提前暴露bean,但是动态代理的过程也要走,鱼和熊掌都要,就使用了这种比较骚气的方式

从上面的代码中,我们可以总结出出现循环依赖时,流程是怎么样的?

  1. addSingletonFactory()方法会将实例化好的空壳对象放在三级缓存中

  2. getSingleton()方法查看到出现循环依赖,会从三级缓存中获取bean,执行定制方法,如果是简单对象,则将简单对象放进二级缓存中,如果是动态代理对象,则将动态代理对象放进二级缓存中

  3. bean生命周期走完后,会把bean放进一级缓存中

测试一下

====

@Controller

public class A {

@Autowired

private B b;

public void test(){

System.out.println(“a”);

}

}

@Controller

public class B {

@Autowired

private A a;

public void test(){

System.out.println(“b”);

}

}

定义一个切面,如果有这个测试类,可以看到调用动态代理方法的过程

@Aspect

@Component

public class AspectDemo {

@Pointcut(“execution(* *.test(…))”)

public void test(){}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/842778.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号