2.1 一级缓存使用的map: private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
2.2 二级缓存使用的map: private final Map<String, Object> earlySingletonObjects = new HashMap(16);
2.3 三级缓存使用的map:?private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
3、Spring容器解决循环依赖简洁概述主要有四大流程方法:获取对象 getSingleton()、?创建对象(实例化) doCreateBean()、填充属性(初始化) populateBean()、返回对象 addSingleton()
在系统启动获取配置文件后,程序是依次读取并加载的,所以上面配置文件代码,先实例化a对象,然后初始化a对象给a添加b属性,再实例化b对象,最后初始化b对象给添加属性a.
那么在代码执行过程中,先调用getSingleton()方法,我们查看源码
@Nullable
public Object getSingleton(String beanName) { // 调用下方重载方法
return this.getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 先从一级缓存中获取a对象的实例
Object singletonObject = this.singletonObjects.get(beanName); // 如果从一级缓存中获取不到a对象,那么检查该对象是否正在被创建,如果正在被创建,则进入if循环中
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) { // 从二级缓存中获取该对象
singletonObject = this.earlySingletonObjects.get(beanName); // 如果二级缓存中无法获取该对象,那么一定会进入如下if方法,因为allowEarlyReference传过来的时候就是true
if (singletonObject == null && allowEarlyReference) { // 从三级缓存中获取该对象
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) { // 如果获取到了该对象,就将三级缓存中的对象放到二级缓存中,并且将三级缓存中的对象删除
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
从三面的源码发现,如果a第一次获取,那么第9行的if语句为false,将直接放回为null,这时回到创建对象doCreateBean()方法,该方法使用反射的方式生成a对象,并且该对象在三级缓存中,对象生成后就需要对a对象进行属性填充:
1 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
2 // 省略多行代码,大致就是调用各种方法,通过反射创建对象
3 try {
4 // a对象创建完成,调用属性填充方法,对a进行属性填充
5 this.populateBean(beanName, mbd, instanceWrapper);
6 exposedObject = this.initializeBean(beanName, exposedObject, mbd);
7 } catch (Throwable var18) {
8 if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
9 throw (BeanCreationException)var18;
10 }
11
12 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
13 }
14
15 if (earlySingletonExposure) {
16 Object earlySingletonReference = this.getSingleton(beanName, false);
17 if (earlySingletonReference != null) {
18 // 省略多行代码
19 }
20 }
22 // 省略多行代码
23 }
在上面代码**doCreateBean()方法中先创建a对象,创建完成后会调用this.populateBean(beanName, mbd, instanceWrapper)**方法对a进行属性填出,这个时候会获取配置文件中所有里面的所有属性,发现会存在一个b属性,下面贴出部分源码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
} else {
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
// 删除大量代码
}
if (continueWithPropertyPopulation) {
// 删除大量源代码,applyPropertyValues方法中beanName为a,pvs为状态各种属性的PropertyValues对象,pvs就装有b这个属性
if (pvs != null) {
this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}
}
}
}
继续跟进applyPropertyValues方法的源码
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (!pvs.isEmpty()) {
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List original;
if (pvs instanceof MutablePropertyValues) {
// 省略大量代码
} else {
original = Arrays.asList(pvs.getPropertyValues());
}
// 省略大量代码 大致过程是将属性对象pvs 转化成original List对象,然后在使用迭代器在下面进行迭代
Iterator var11 = original.iterator();
while(true) {
while(var11.hasNext()) {
PropertyValue pv = (PropertyValue)var11.next();
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
// 通过下面方法解决依赖的b,整个方法在迭代器中,外层在while(true)中,可能有多个属性,循环直到所有属性都解决了就return;或者抛出异常
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// 省略大量代码
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
return;
} catch (BeansException var19) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
}
}
}
}
继续跟进上面红色方法
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference)value;
return this.resolveReference(argName, ref);
} else if (value instanceof RuntimeBeanNameReference) {
// 省略多行代码
}
// 省略多行代码
}
继续跟进红色部分的代码
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName();
refName = String.valueOf(this.doEvaluate(refName));
Object bean;
if (ref.isToParent()) {
// 省略多行代码
# 2021年Java中高级面试必备知识点总结
在这个部分总结了2019年到目前为止Java常见面试问题,取其面试核心编写成这份文档笔记,从中分析面试官的心理,摸清面试官的“套路”,可以说搞定90%以上的Java中高级面试没一点难度。
本节总结的内容涵盖了:消息队列、Redis缓存、分库分表、读写分离、设计高并发系统、分布式系统、高可用系统、SpringCloud微服务架构等一系列互联网主流高级技术的知识点。
**目录:**
![](https://img-blog.csdnimg.cn/img_convert/0c30527fdc017963a02fb4d16fa89004.png)
(上述只是一个整体目录大纲,每个点里面都有如下所示的详细内容,从面试问题——分析面试官心理——剖析面试题——完美解答的一个过程)
![](https://img-blog.csdnimg.cn/img_convert/04c4f634ef500aca2280da5333c47967.png)
**部分内容:**
![](https://img-blog.csdnimg.cn/img_convert/4a1266bce58f54a47fa929c6f835039b.png)
![](https://img-blog.csdnimg.cn/img_convert/ce6f828b3c246ccf2bd656233458bdc2.png)
![](https://img-blog.csdnimg.cn/img_convert/7bd9e893bb983bada2e50d37b3fb1754.png)
对于每一个做技术的来说,学习是不能停止的,小编把2019年到目前为止Java的核心知识提炼出来了,无论你现在是处于什么阶段,如你所见,这份文档的内容无论是对于你找面试工作还是提升技术广度深度都是完美的。
不想被后浪淘汰的话,赶紧搞起来吧,**高清完整版一共是888页,需要的话可以点赞+关注后,[点击这里免费获取](https://codechina.csdn.net/m0_60958482/java-p7)!**
为止Java的核心知识提炼出来了,无论你现在是处于什么阶段,如你所见,这份文档的内容无论是对于你找面试工作还是提升技术广度深度都是完美的。
不想被后浪淘汰的话,赶紧搞起来吧,**高清完整版一共是888页,需要的话可以点赞+关注后,[点击这里免费获取](https://codechina.csdn.net/m0_60958482/java-p7)!**
|