青岛做公司网站的多吗建筑企业设计公司
- 作者: 五速梦信息网
- 时间: 2026年03月21日 09:54
当前位置: 首页 > news >正文
青岛做公司网站的多吗,建筑企业设计公司,优质的武进网站建设,网站后台地址修改文章目录 关键代码相关知识为什么要使用二级缓存为什么要使用三级缓存只使用两个缓存的问题不能解决构造器循环依赖为什么多例bean不能解决循环依赖问题初始化后代理对象赋值给原始对象解决循环依赖SpringBoot开启循环依赖 循环依赖 在线流程图 关键代码 从缓存中查询getSingl… 文章目录 关键代码相关知识为什么要使用二级缓存为什么要使用三级缓存只使用两个缓存的问题不能解决构造器循环依赖为什么多例bean不能解决循环依赖问题初始化后代理对象赋值给原始对象解决循环依赖SpringBoot开启循环依赖 循环依赖 在线流程图 关键代码 从缓存中查询getSingleton()方法 protected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lock// 一级缓存 二级缓存中取Object singletonObject this.singletonObjects.get(beanName);if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton lock// 加锁后再查询 重新取一遍singletonObject this.singletonObjects.get(beanName);if (singletonObject null) {singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null) {ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {singletonObject singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject; }经过单例Bean判断和是否允许开启依赖注入判断后往第三级缓存中存ObjectFactory函数式接口对象 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);}// 循环依赖-添加到三级缓存addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean)); }初始化后将循环依赖产生的代理对象赋值给普通对象 if (earlySingletonExposure) {// 从二级缓存中取代理对象Object earlySingletonReference getSingleton(beanName, false);if (earlySingletonReference ! null) {// 赋值给当前普通对象if (exposedObject bean) {exposedObject earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping hasDependentBean(beanName)) {// beanName被哪些bean依赖了现在发现beanName所对应的bean对象发生了改变那么则会报错String[] dependentBeans getDependentBeans(beanName);SetString actualDependentBeans new LinkedHashSet(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,Bean with name beanName has been injected into other beans [ StringUtils.collectionToCommaDelimitedString(actualDependentBeans) ] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using getBeanNamesForType with the allowEagerInit flag turned off, for example.);}}}}相关知识 案例A对象 与 B对象互相引用A对象 与 C对象互相引用。 为什么要使用二级缓存 作用 二级缓存中存储的是不完整的早期的bean。二级缓存使不完整的bean和完整的bean分开存储保证并发线程安全提高性能 假如不使用二级缓存只有一级缓存的情况。一级缓存它想要打破循环的话就只能把半成品Bean存放在一级缓存中这样创建B对象时就获取到一级缓存中的半成品A对象了这样也就打破了对象互相引用的死循环。 问题是多线程访问时其他线程可能就拿到了A对象取使用了。 解决方法是对整个getBean()方法加锁这样的问题是锁的粒度太大了而且想获取已经创建好了的对象也需要等待 所以就加入了二级缓存用二级缓存来降低锁的粒度提升性能 为什么要使用三级缓存 作用 解决循环依赖的死循环使用ObjectFactory函数式接口提升bean创建过程扩展性保证规范代码职责单一性 如果不使用三级缓存同时A对象要进行AOP的话此时就会出现依赖注入给B对象中的属性的A的普通对象A经过创建过程之后存入单例池的却是代理对象 如果想要解决上面的问题就需要在创建bean对象的过程中在实例化之后属性填充之前就进行AOP操作生成代理对象并存入二级缓存中。 这种方式就破坏了Bean创建过程的规范同时还会出现循环依赖多次创建多次动态代理对象。 所以解决方法是我只判断出现了循环依赖这种情况才对该bean提前进行AOP操作。这些操作代码我不能加在创建bean的各个小步骤中为了保证代码职责单一性。所以便有了三级缓存来保存ObjectFactory函数式接口对象在出现了循环依赖的情况下就去执行对应方法。 只使用两个缓存的问题 如果只使用一级和二级缓存那么就需要考虑AOP问题可能给对象B注入的是普通对象存入单例池是的代理对象 如果只使用一级和三级缓存A对象与B对象互相引用A对象与C对象互相引用。在执行行A对象就会创建两个AOP代理对象分别注入给B和C 不能解决构造器循环依赖 因为在创建Bean的总流程中先进行实例化完成之后才会去往三级存储中存入数据。此时实例化都没有完成普通对象都没有创建成功所以无法处理 解决方法是使用Lazy注解 为什么多例bean不能解决循环依赖问题 我们从源码中是可以发现再往三级缓存中存数据前是进行了if判断的只有单例bean才会加入到三级缓存中。 其实解决循环依赖核心就是使用了一个Map而这个map就相当于一个缓存。 我们bean是单例的而且注入是通过setter字段注入的单例意味着只需要创建一次对象后续就可以从缓存中取出来字段注入意味着我们无需调用构造方法进行注入。 如果是原型Bean那么意味着每次都要去创建bean无法利用缓存如果是构造方法注入那么意味着需要调用构造方法注入也无法利用缓存 初始化后代理对象赋值给原始对象 在bean的创建过程中还有一个地方跟循环依赖有关。 如果A是动态代理对象通过三级缓存循环依赖之后就会出现B.a A的代理对象。但进行了初始化整个过程的A对象是普通对象所以此时就需要把二级缓存中的代理对象赋值给BeanA。 if (earlySingletonExposure) {// 1. 从二级缓存中取出代理对象Object earlySingletonReference getSingleton(beanName, false);if (earlySingletonReference ! null) {// 2. 赋值给普通对象// 这里会判断初始化过程中是否改变了当前对象如果改变了则下面的if判断不成立if (exposedObject bean) {exposedObject earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping hasDependentBean(beanName)) {// beanName被哪些bean依赖了现在发现beanName所对应的bean对象发生了改变那么则会报错String[] dependentBeans getDependentBeans(beanName);SetString actualDependentBeans new LinkedHashSet(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,Bean with name beanName has been injected into other beans [ StringUtils.collectionToCommaDelimitedString(actualDependentBeans) ] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using getBeanNamesForType with the allowEagerInit flag turned off, for example.);}}}}Async注解会在初始化过程中创建动态代理对象导致上面if判断中得到的代理对象和原始bean对象不一致。故而抛出异常Transactional注解也是代理对象为什么不会报错这是因为Transaction注解的代理对象和AOP实际上是一个代理对象。 在解决循环依赖时我就通过了普通对象创建了一个代理对象解决你在初始化过程中有改变了普通对象那我之前创建的代理对象岂不是没用了。 解决循环依赖 如果关闭了循环依赖功能如果有两种方式解决循环依赖 使用Lazy注解加在属性上代表Spring容器加载时注入会临时注入一个代理对象等真正使用的时候再通过代理对象去调用最终的getBean()方法添加一个中间类 中间类去依赖A\B 然后让中间类去组织他们的依赖方法 SpringBoot开启循环依赖 不建议开启能产生循环依赖问题的代码本身就是一种不规范的设计。 Spring作者都已表示可能会在后续版本去掉循环依赖支持。 除非你是把 Spring代码移植到SpringBoot 可以考虑开启循环依赖已保证之前代码正常性。 spring.main.allow-circular-referencestrue
- 上一篇: 青岛装修装饰公司网站建设到哪里查网站备案信息
- 下一篇: 青岛做商城网站免费网络电话呼叫系统
相关文章
-
青岛装修装饰公司网站建设到哪里查网站备案信息
青岛装修装饰公司网站建设到哪里查网站备案信息
- 技术栈
- 2026年03月21日
-
青岛专业网站建设定制沧州 网站建设
青岛专业网站建设定制沧州 网站建设
- 技术栈
- 2026年03月21日
-
青岛注册公司核名在哪个网站怎么用一级域名搭建网站
青岛注册公司核名在哪个网站怎么用一级域名搭建网站
- 技术栈
- 2026年03月21日
-
青岛做商城网站免费网络电话呼叫系统
青岛做商城网站免费网络电话呼叫系统
- 技术栈
- 2026年03月21日
-
青岛做外贸网站哪家好吉林平台网站建设推荐
青岛做外贸网站哪家好吉林平台网站建设推荐
- 技术栈
- 2026年03月21日
-
青岛做网站的公司哪家好wordpress健身预定主题
青岛做网站的公司哪家好wordpress健身预定主题
- 技术栈
- 2026年03月21日






