很难出错的Spring5(十)—— IOC进阶

一、Bean的生命周期

  • 创建:就是执行new,构造方法
  • 依赖注入/属性注入
    • 指的就是@Autowired注解的这些变量
    • 从三级缓存里拿
  • 初始化
    • 算出来一些以后肯定会用到的东西
    • 用@PostConstruct注解生命的方法在这个时候执行
  • 销毁。相当于把引用赋值为null,就可以被回收了

二、单例Bean的线程安全问题

spring默认bean是单例的,你可以认为"资源只有一份",比如某个Service类加了@Service注解,那么这个service的实例只有一份,当很多个请求进来的时候,都一起用这个实例,就要考虑bean的线程安全问题。有这么几种防御式编程的手段

  • synchronized关键字
  • ThreadLocal
  • 除了static类变量、final变量、以及@Autowired注入的变量之外。其余变量不许出现在成员变量里,只能出现在每个方法的内部。
  • 修改作用域,把单例改成prototype

三、如何解决循环依赖问题?

循环依赖:A类里用@Autowired注入了B类的实例,B类用@Autowired注入了A类的实例

解决方式:借用spring的三级缓存,底层逻辑是"提前暴露半成品"。

  • 一级:放bean成品
  • 二级:放未注入属性的半成品
  • 三级:工厂库。主要解决AOP带来的问题

创建完A的bean,A先在三级缓存里放一个自己的A工厂实例,准备依赖注入B的实例的时候,于是去Spring一级缓存一直找到三级缓存找B,发现B还没有被创建出来,所以去实例化B。B实例经过创建阶段,(B也在三级缓存放一个自己的工厂实例,但是因为本次叙述是A打头的,所以没用到),走入依赖注入阶段,开始从缓存里找A的实例,从一级缓存开始找一直找到三级缓存,发现可以在三级缓存中通过对象工厂拿到A,虽然A不太完善,但是已经存在,就把A放入二级缓存,同时删除三级缓存中的A,此时B已经完成注入了,成为一个成品,于是把B放入一级缓存。接着对A进行注入,现在A可以从一级缓存拿到B了,此时A也完成了注入成为了一个成品,于是删除二级缓存里的A,把A放入一级缓存。

总感觉跟"分布式事务"、"两阶段提交"、"TCP三次握手"这些思想的底层逻辑有点像,因为都有"半成品"出现。感觉第三级缓存就像是用来做标记用的。跟解决死锁的思路也很像

3.1 为什么需要三级缓存?

因为A这个类可能被@Transactional注解修饰或者自定义切面 @Aspect 能匹配到 A 类中的方法,也就是A生成的实例bean并不是原生的,而是一个代理实例。如果只有一二级缓存的话,B拿到的是原生实例,而A最后生成并放到一级缓存里的是代理实例,二者不一致了。

所以B去获取A实例的时候,就得获取一个反射的代理实例,所以需要再来一个缓存,专门存工厂。

相关推荐
麦麦麦当劳大王13 小时前
【油猴脚本】Boss直聘 岗位职责复制
开发语言·前端·javascript
starzy199013 小时前
深入理解Scala Map:从实现原理到工程实践
开发语言·后端·scala
只睡四小时14 小时前
Three.js Sub-tick:漏判 60.7%→0
开发语言·javascript·性能优化·ecmascript·游戏开发·three.js·碰撞检测
码农小河6615 小时前
基于SSM+JSP的高校专业信息管理系统【附源码+数据库】
java·开发语言·数据库
东鹏特饮17 小时前
系统运维(传统/通用运维)面试题
开发语言·php
风若飞17 小时前
Spring Ai 入门遇到问题1
java·后端·spring
今天要早睡_17 小时前
C++01_入门基础复习
开发语言·c++
Nuanyt17 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
黑马程序员毕设18 小时前
基于 Java 的餐饮点餐系统设计与应用报告
java·开发语言
SL_staff18 小时前
从文档工具到知识中枢:基于JVS数字底座构建企业级统一内容管理平台的技术实践
java·开源·全栈