java高级面试问题大全及答案大全,帮你深度探寻Spring循环依赖源码实现,java高级工程师面试视频

} else if (mbd.isPrototype()) {
…忽略不必要代码…
} else {
…忽略不必要代码…
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

if (requiredType != null && !requiredType.isInstance(bean)) {
…忽略不必要代码…
}
return (T) bean;
}

  • 之前手写了一遍解决循环依赖的代码,这里是不是很熟悉?这就是在缓存里面寻找对应的bean,当缓存有的时候直接返回,没有的时候才去创建!相信聪明的你一定若有所思!  这里极其重要,咱们进入到createBean里面

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
…忽略不必要代码…
try {
//真正干活的方法来了 呵呵呵呵 反射创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//…忽略不必要代码…
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
//先前检测到的具有正确的bean创建上下文的异常,
//或非法的单例状态,最多可以传达给DefaultSingletonBeanRegistry。
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, “Unexpected exception during bean creation”, ex);
}
}

  • 进入到doCreateBean里面

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {

// 实例化bean。
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//开始创建bean 的逻辑 这里实际上该类已经被实例化了 只不过返回的是一个包装对象,包装对象内部存在该实例化好的对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//获取之前创建的bean
final Object bean = instanceWrapper.getWrappedInstance();

…忽略不必要代码…

//判断当前这个对象是不是单例 是不是支持循环引用 是不是正在创建中 满足这几个条件才会放置到三级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences
&&isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
…忽略不必要代码…

//这个方法时将当前实例号的bean放置到三级缓存 三级缓存内部存放的时 beanName -> bean包装对象 这个样的kv键值对
//设置这个方法的目的时 Spring设计时是期望Spring再bean实例化之后去做代理对象的操作,而不是再创建的时候就判断是否 是代理对象
//但实际上如果发生了循环引用的话,被依赖的类就会被提前创建出来,并且注入到目标类中,为了保证注入的是一个实际的代理对象
//所以Spring来了个偷天换日,偷梁换柱
//后续需要注入的时候,只需要通过工厂方法返回数据就可以了,在工厂里面可以做代理相关的操作,执行完代理操作后,在返回对象
//符合了Spring设计时,为了保证代理对象的包装再Springbean生命周期的后几步来实现的预期
//这一步还会删除二级缓存的数据
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// 初始化bean实例。
Object exposedObject = bean;
try {
//填充内部的属性
//☆这一步解决了循环依赖的问题,在这里发生了自动注入的逻辑
populateBean(beanName, mbd, instanceWrapper);
//执行初始化的逻辑 以及生命周期的回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
…忽略不必要代码…
}

if (earlySingletonExposure) {
…忽略不必要代码…
}
…忽略不必要代码…
return exposedObject;
}

  • 进入到populateBean 方法,这里执行属性注入,同时也解决了循环依赖!

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
…忽略不必要代码…

// 给任何InstantiationAwareBeanPostProcessors修改机会,
// 设置属性之前Bean的状态。例如,可以使用它
// 支持场注入方式。
boolean continueWithPropertyPopulation = true;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
…忽略不必要代码…
}
}

if (!continueWithPropertyPopulation) {
return;
}
…忽略不必要代码…
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//因为是使用@Autowired注解做的自动注入
// 故而Spring会使用 AutowiredAnnotationBeanPostProcessor.postProcessProperties来处理自动注入
//事实上这一步是会做注入处理的,这个也是我们重点观察的对象
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
…忽略不必要代码…
}
}
}
if (needsDepCheck) {
…忽略不必要代码…
}

if (pvs != null) {
//开始设置属性值 mbd是依赖的bean
applyPropertyValues(beanName, mbd, bw, pvs);
}
}

进入到 AutowiredAnnotationBeanPostProcessor.postProcessProperties

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
…忽略不必要代码…
try {
//注入逻辑
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, “Injection of autowired dependencies failed”, ex);
}
return pvs;
}

  • 进入到inject

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection checkedElements = this.checkedElements;
Collection elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
…忽略不必要代码…
//注入逻辑发生的实际代码 因为是属性注入,所以 使用AutowiredFieldElement.inject
element.inject(target, beanName, pvs);
}
}
}

  • 进入到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//获取需要注入的属性对象
Field field = (Field) this.member;
Object value;
…忽略不必要代码…
else {
…忽略不必要代码…
try {
//真正的解决依赖的代码,查找依赖创建依赖的代码
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
…忽略不必要代码…
}
if (value != null) {
//反射的注入逻辑
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}

  • 此时别说你们我都想说一句wo cao终于看到希望了,这里由 beanFactory.resolveDependency获取即将要注入的对象,然后后面通过反射注入到对象里面去,我们是不是只需要知道beanFactory.resolveDependency里面的逻辑就可以知道循环依赖的问题了?我们果断进去看看果然发现还没完:

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
…忽略不必要代码…
if (result == null) {
//解决依赖性 这个是实际干活的方法
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}

进入到 doResolveDependency

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

…忽略不必要代码…
//根据类型和名称查询该bean的数据
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
…忽略不必要代码…
//这一步是真正创建一个类这里面会调用getBean方法重新的走上面的那一套创建bean的逻辑
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

image

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

image

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值