当前位置: 首页 > 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);Set<String> 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);Set<String> 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实际上是一个代理对象。

在解决循环依赖时,我就通过了普通对象创建了一个代理对象,解决你在初始化过程中有改变了普通对象,那我之前创建的代理对象岂不是没用了。



解决循环依赖

如果关闭了循环依赖功能,如果有两种方式解决循环依赖

  1. 使用@Lazy注解加在属性上,代表Spring容器加载时注入,会临时注入一个代理对象,等真正使用的时候再通过代理对象去调用最终的getBean()方法
  2. 添加一个中间类, 中间类去依赖A\B, 然后让中间类去组织他们的依赖方法

在这里插入图片描述



SpringBoot开启循环依赖

不建议开启,能产生循环依赖问题的代码本身就是一种不规范的设计。

Spring作者都已表示可能会在后续版本去掉循环依赖支持。 除非你是把 Spring代码移植到SpringBoot ,可以考虑开启循环依赖已保证之前代码正常性。

spring.main.allow-circular-references=true
http://www.ds6.com.cn/news/53348.html

相关文章:

  • 宜兴做网站软文推广渠道主要有
  • 中国最好网站建设公司深圳广告投放公司
  • 类似饿了么的网站怎么做南宁网站建设及推广
  • 如何做网站赚热门搜索关键词
  • web前端的就业前景seo技巧是什么意思
  • 网站设置301重定向杭州营销策划公司排名
  • 快站淘客建网站怎么建
  • 太平桥网站建设百度快照搜索
  • 网站建设分析报告南京seo优化
  • 揭阳住房和城乡建设厅网站济南网站制作公司
  • 可以做动画的网站都有哪些seo怎么优化简述
  • 西安微信平台网站建设百度排行榜风云
  • 黄金网站app免费视频大全网站收录申请
  • 传统网站和手机网站的区别怎么样优化关键词排名
  • 协会网站建设制作廊坊首页霸屏排名优化
  • 网站建设市场需求分析二维码引流推广的平台
  • 青岛市做网站优化怎么做网站优化排名
  • 做网站的分辨率是72吗国际新闻网
  • 靖江网站推广搜索量查询百度指数
  • 安徽建设厅证书查询网网站怎么做业务推广技巧
  • 网站分站开发计划书seoul什么意思
  • 游戏分类网站怎么做seo关键词怎么选择
  • 个人博客网站需求分析chrome 谷歌浏览器
  • 有关中国文明网联盟网站建设活动方案百度广告平台
  • 专业做网站流程网络营销就是seo正确吗
  • 淮北市建设安全监督站网站搜索引擎优化宝典
  • 做网站如何与美工配合设计一个公司网站多少钱
  • 做网站怎么写代码万能搜索引擎网站
  • 如何开科技网站搜索引擎优化情况怎么写
  • wordpress常常被用来做什么网站百度指数如何提升