当前位置: 首页 > news >正文

投资网站开发wordpress安装用户名密码

投资网站开发,wordpress安装用户名密码,聊天网站站怎么做,遵义网站建设服务✅作者简介#xff1a;大家好#xff0c;我是Leo#xff0c;热爱Java后端开发者#xff0c;一个想要与大家共同进步的男人#x1f609;#x1f609; #x1f34e;个人主页#xff1a;Leo的博客 #x1f49e;当前专栏#xff1a;每天一个知识点 ✨特色专栏#xff1a… ✅作者简介大家好我是Leo热爱Java后端开发者一个想要与大家共同进步的男人 个人主页Leo的博客 当前专栏每天一个知识点 ✨特色专栏 MySQL学习 本文内容第04天 Spring是如何解决循环依赖的 ️个人小站 个人博客欢迎大家访问 个人知识库 知识库欢迎大家访问 1. 什么是循环依赖 就是A对象依赖了B对象B对象依赖了A对象。 说白是一个或多个对象实例之间存在直接或间接的依赖关系这种依赖关系构成了构成一个环形调用。 // A依赖了B class A{public B b; }// B依赖了A class B{public A a; } 那么循环依赖是个问题吗 如果不考虑Spring循环依赖并不是问题因为对象之间相互依赖是很正常的事情。 比如 A a new A(); B b new B();a.b b; b.a a;这样A,B就依赖上了。 但是在Spring中循环依赖就是一个问题了为什么 因为在Spring中一个对象并不是简单new出来了而是会经过一系列的Bean的生命周期就是因为Bean的生命周期所以才会出现循环依赖问题。当然在Spring中出现循环依赖的场景很多有的场景Spring自动帮我们解决了而有的场景则需要程序员来解决下文详细来说。 要明白Spring中的循环依赖得先明白Spring中 Bean的生命周期。 2. Bean的生命周期 Bean的生命周期指的就是在Spring中Bean是如何生成的 被Spring管理的对象叫做Bean。Bean的生成步骤如下 Spring扫描class得到BeanDefinition根据得到的BeanDefinition去生成bean首先根据class推断构造方法根据推断出来的构造方法反射得到一个对象暂时叫做原始对象填充原始对象中的属性依赖注入如果原始对象中的某个方法被AOP了那么则需要根据原始对象生成一个代理对象把最终生成的代理对象放入单例池源码中叫做singletonObjects中下次getBean时就直接从单例池拿即可 可以看到对于Spring中的Bean的生成过程步骤还是很多的并且不仅仅只有上面的7步还有很多很多比如Aware回调、初始化等等这里不详细讨论。 可以发现在Spring中构造一个Bean包括了new这个步骤第4步构造方法反射。得到一个原始对象后Spring需要给对象中的属性进行依赖注入那么这个注入过程是怎样的 比如上文说的A类A类中存在一个B类的b属性所以当A类生成了一个原始对象之后就会去给b属性去赋值此时就会根据b属性的类型和属性名去BeanFactory中去获取B类所对应的单例bean。如果此时BeanFactory中存在B对应的Bean那么直接拿来赋值给b属性如果此时BeanFactory中不存在B对应的Bean则需要生成一个B对应的Bean然后赋值给b属性。 问题就出现在第二种情况如果此时B类在BeanFactory中还没有生成对应的Bean那么就需要去生成就会经过B的Bean的生命周期。 那么在创建B类的Bean的过程中如果B类中存在一个A类的a属性那么在创建B的Bean的过程中就需要A类对应的Bean但是触发B类Bean的创建的条件是A类Bean在创建过程中的依赖注入所以这里就出现了循环依赖 ABean创建–依赖了B属性–触发BBean创建—B依赖了A属性—需要ABean但ABean还在创建过程中从而导致ABean创建不出来BBean也创建不出来。这是循环依赖的场景但是上文说了在Spring中通过某些机制帮开发者解决了部分循环依赖的问题这个机制就是三级缓存。 3. 三级缓存 三级缓存是通用的叫法。 一级缓存为singletonObjects 二级缓存为earlySingletonObjects 三级缓存为singletonFactories 先稍微解释一下这三个缓存的作用 singletonObjects中缓存的是已经经历了完整生命周期的bean对象。 earlySingletonObjects比singletonObjects多了一个early表示缓存的是早期的bean对象。早期是什么意思表示Bean的生命周期还没走完就把这个Bean放入earlySingletonObjects。 singletonFactories中缓存的是ObjectFactory表示对象工厂用来创建某个对象的。 4. 分析 先来分析为什么缓存能解决循环依赖。 上文分析得到之所以产生循环依赖的问题主要是 A创建时—需要B----B去创建—需要A从而产生了循环 下面用一张图告诉你spring是如何解决循环依赖的 A的Bean在创建过程中在进行依赖注入之前先把A的原始Bean放入缓存提早暴露只要放到缓存了其他Bean需要时就可以从缓存中拿了放入缓存后再进行依赖注入此时A的Bean依赖了B的Bean如果B的Bean不存在则需要创建B的Bean而创建B的Bean的过程和A一样也是先创建一个B的原始对象然后把B的原始对象提早暴露出来放入缓存中然后在对B的原始对象进行依赖注入A此时能从缓存中拿到A的原始对象虽然是A的原始对象还不是最终的BeanB的原始对象依赖注入完了之后B的生命周期结束那么A的生命周期也能结束。 因为整个过程中都只有一个A原始对象所以对于B而言就算在属性注入时注入的是A原始对象也没有关系因为A原始对象在后续的生命周期中在堆中没有发生变化。 从上面这个分析过程中可以得出只需要一个缓存就能解决循环依赖了那么为什么Spring中还需要singletonFactories呢 这是难点基于上面的场景想一个问题如果A的原始对象注入给B的属性之后A的原始对象进行了AOP产生了一个代理对象此时就会出现对于A而言它的Bean对象其实应该是AOP之后的代理对象而B的a属性对应的并不是AOP之后的代理对象这就产生了冲突。 **B依赖的A和最终的A不是同一个对象。 ** 那么如何解决这个问题这个问题可以说没有办法解决。 因为在一个Bean的生命周期最后Spring提供了BeanPostProcessor可以去对Bean进行加工这个加工不仅仅只是能修改Bean的属性值也可以替换掉当前Bean。 举个例子 Component public class User { }Component public class TestBeanPostProcessor implements BeanPostProcessor {Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 生成了一个新的User对象if (beanName.equals(user)) {System.out.println(bean);User user new User();return user;}return bean;} }public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);User user context.getBean(user, User.class);System.out.println(user);} }运行main方法得到的打印如下 com.test.service.User67gh4rt3 com.test.service.User56tr75b3所以在BeanPostProcessor中可以完全替换掉某个beanName对应的bean对象。 而BeanPostProcessor的执行在Bean的生命周期中是处于属性注入之后的循环依赖是发生在属性注入过程中的所以很有可能导致注入给B对象的A对象和经历过完整生命周期之后的A对象不是一个对象。这就是有问题的。 所以在这种情况下的循环依赖Spring是解决不了的因为在属性注入时Spring也不知道A对象后续会经过哪些BeanPostProcessor以及会对A对象做什么处理。 5. Spring解决了哪种循环依赖 虽然上面的情况可能发生但是肯定发生得很少我们通常在开发过程中不会这样去做但是某个beanName对应的最终对象和原始对象不是一个对象却会经常出现这就是AOP。 AOP就是通过一个BeanPostProcessor来实现的这个BeanPostProcessor就是AnnotationAwareAspectJAutoProxyCreator它的父类是AbstractAutoProxyCreator而在Spring中AOP利用的要么是JDK动态代理要么CGLib的动态代理所以如果给一个类中的某个方法设置了切面那么这个类最终就需要生成一个代理对象。 一般过程就是A类—生成一个普通对象–属性注入–基于切面生成一个代理对象–把代理对象放入singletonObjects单例池中。 而AOP可以说是Spring中除开IOC的另外一大功能而循环依赖又是属于IOC范畴的所以这两大功能想要并存Spring需要特殊处理。 如何处理的就是利用了第三级缓存singletonFactories。 首先singletonFactories中存的是某个beanName对应的ObjectFactory在bean的生命周期中生成完原始对象之后就会构造一个ObjectFactory存入singletonFactories中。这个ObjectFactory是一个函数式接口所以支持Lambda表达式() - getEarlyBeanReference(beanName, mbd, bean) 上面的Lambda表达式就是一个ObjectFactory执行该Lambda表达式就会去执行getEarlyBeanReference方法而该方法如下 protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject bean;if (!mbd.isSynthetic() hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp (SmartInstantiationAwareBeanPostProcessor) bp;exposedObject ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject; }该方法会去执行SmartInstantiationAwareBeanPostProcessor中的getEarlyBeanReference方法而这个接口下的实现类中只有两个类实现了这个方法一个是AbstractAutoProxyCreator一个是InstantiationAwareBeanPostProcessorAdapter它的实现如下 // InstantiationAwareBeanPostProcessorAdapter Override public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {return bean; }// AbstractAutoProxyCreator Override public Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey); }所以很明显在整个Spring中默认就只有AbstractAutoProxyCreator真正意义上实现了getEarlyBeanReference方法而该类就是用来进行AOP的。上文提到的AnnotationAwareAspectJAutoProxyCreator的父类就是AbstractAutoProxyCreator。 那么getEarlyBeanReference方法到底在干什么 首先得到一个cachekeycachekey就是beanName。 然后把beanName和bean这是原始对象存入earlyProxyReferences中 调用wrapIfNecessary进行AOP得到一个代理对象。 那么什么时候会调用getEarlyBeanReference方法呢回到循环依赖的场景中 三级缓存放的并不是代理对象是ObjectFactory对象且传递了函数式接口getEarlyBeanReference方法作为该对象getObject方法的内部实现getEarlyBeanReference方法是一处Bean后置处理器SmartInstantiationAwareBeanPostProcessor的使用接口方法getEarlyBeanReference可以拓展代理对象的创建这种情况我感觉是为了避免两个代理对象的循环依赖问题例如A、B相互依赖且都需要创建AOP代理对象此时如果按照不做处理getBean(A)填充B即getBean(B)B填充A此时B填充了A的真实对象然后B完成getBean周期初始化后创建了代理对象PB并且返回A填充的B是B的代理对象PB但是B填充的确是普通的A所以才会在后置处理器SmartInstantiationAwareBeanPostProcessor的实现类里提供了getEarlyBeanReference方法来提前创建代理对象这样一来AB填充的都是BA的代理对象当然代理对象创建后会放入缓存避免初始化后重复创建代理对象 //处理AOP的后置处理器实现的抽象类AbstractAutoProxyCreator public Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);//提前触发代理对象的创建return wrapIfNecessary(bean, beanName, cacheKey); }考虑到如果有代理对象的创建需要放到一级缓存的就应该是代理对象而非target对象所以在初始化完成后需要判断下是否创建了代理对象从而确定向一级缓存是代理对象如果创建了的话如下代码块getSingleton方法会拿到二级缓存里的Bean对象正常情况下就是targetBean如果创建了代理对象二级缓存里就是代理对象了如果不涉及循环依赖放到一级里的exposedObject就是正确的Bean作为初始化的返回值在初始化方法里创建了代理对象那么也没影响代理对象会被正常放入一级如果同时涉及到AOP和循环代理就会触发如下条件由于提前创建代理对象初始化方法并不会重复创建所以满足exposedObject bean所以此时二级缓存里通过getEarlyBeanReference创建的代理对象需要放入一级而非exposedObject所以执行 exposedObject earlySingletonReference; Object earlySingletonReference getSingleton(beanName, false); if (earlySingletonReference ! null) {//正常相等//只涉及AOP不等不需要处理//同时循环和AOP需要纠正为getEarlyBeanReference创建的代理对象if (exposedObject bean) {//如果循环依赖创建提前创建了那么此时初始化后不会重复创建所以exposedObject和bean是相等的exposedObject earlySingletonReference;//因此直接替换为提前创建的代理对象作为放入一级缓存的对象}
http://www.zqtcl.cn/news/18449/

相关文章:

  • 阳泉住房和城乡建设厅网站做远程培训网站用什么系统
  • 购物网站订单状态模板旅游网站建设那家好
  • 大连智能模板建站做网站很累
  • 查权重网站jquery特效的网站
  • wordpress站点很慢百seo排名优化
  • 岫岩洋河网站建设广州市城乡和建设局网站首页
  • 温州平阳县营销型网站建设好搜网站提交入口
  • 吉安律师网站建设app找什么公司
  • 空调网站模板赣州金图网络科技有限公司
  • 深圳网站建设ejiew淘宝网页版登录入口官方
  • 贵南县网站建设公司seo案例分析方案
  • 内蒙古建设厅网站在线设计平台的用户群分析
  • php建站软件哪个好傻瓜式php网站开发
  • 新公司网站建设费用怎么入账wordpress价钱
  • 新站整站排名优化火速公司wordpress require_once
  • 郑州网站建设修改seo优化百度自然排名
  • 网站建设 美词公司网站建设合同要交印花税吗
  • 网站logo如何做链接上海公司起名
  • 网站轮播图制作网站模板论坛
  • 做网站设计需要多少钱开发公司工作总结
  • 阿里巴巴 网站 建设如何完整地备份wordpress
  • 重庆做网站重庆做网站wordpress按修改时间排序
  • 做视频网站需要流量手机站喝茶影视
  • 服装网站建设开发语言wordpress 添加附件
  • 如何保护网站名百度seo提高排名费用
  • php酒店网站源码个人博客排名
  • 找钢网网站建设政务服务平台
  • 北京网站维护一般价格多少wordpress安装指南
  • 网页设计样图苏州seo快速优化
  • 手机网站设计建设服务网站建设的网