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

成都市网站建设新网站域名备案流程

成都市网站建设,新网站域名备案流程,wap网站 区别,网站源码是什么循环依赖是之前很爱问的一个面试题#xff0c;最近不咋问了#xff0c;但是梳理Spring解决循环依赖的源码#xff0c;会让我们对Spring创建bean的流程有一个清晰的认识#xff0c;有必要搞一搞。开始搞之前#xff0c;先参考了这个老哥写的文章#xff0c;对Spring处理循…循环依赖是之前很爱问的一个面试题最近不咋问了但是梳理Spring解决循环依赖的源码会让我们对Spring创建bean的流程有一个清晰的认识有必要搞一搞。开始搞之前先参考了这个老哥写的文章对Spring处理循环依赖有了一个基本的认识之后然后开始进行源码debug感谢这位老哥的分享https://developer.aliyun.com/article/766880 我们搞一个简单的例子先看看什么是循环依赖我们只讲最简单的这种set方法循环依赖除此之外还有构造器循环依赖我们讲最简单的这种其实道理是一样的。 搞一个demo Data Component public class TestA {Autowiredprivate TestB testB;public void getA(){System.out.println(我是getA方法);} }Data Component public class TestB {Autowiredprivate TestA testA; }A依赖BB依赖A。这样就形成了一个简单的循环依赖。众所周知Spring解决循环依赖的经典方法是三级缓存当然还有其他的方法也可以处理比如懒加载。今天我们只聊三级缓存其他方式感兴趣的话可以自己查一些资料。 如果之前看过Spring的代码我们就知道Spring在创建bean之前都会先获取bean如果获取不到才会创建bean。所以我们从获取bean开始看起。 获取bean的入口在AbstractBeanFactory的doGetBean方法中。第一行代码我们先看到从缓存获取bean的流程 // Eagerly check singleton cache for manually registered singletons. Object sharedInstance getSingleton(beanName);这个方法里我们想看的三级缓存就全了 protected Object getSingleton(String beanName, boolean allowEarlyReference) {//先从一级缓存取Object singletonObject this.singletonObjects.get(beanName);if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {//一级缓存没有,从二级缓存取singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null allowEarlyReference) {//二级缓存没有,从三级缓存取ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {singletonObject singletonFactory.getObject();//三级缓存取出来之后放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);//从三级缓存移除this.singletonFactories.remove(beanName);}}}}return singletonObject;}刚开始这三个缓存里肯定都没有父容器中也不会有。所以此时需要创建A。 创建A的流程也在doGetBean方法里我们向下看有这样一段逻辑 // Create bean instance. if (mbd.isSingleton()) {sharedInstance getSingleton(beanName, () - {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {}}); }createBean就是创建一个bean但是这个createBean的过程是getSingleton方法的一个参数是一个工厂方法也就是说先执行getSingleton方法某一个时机下再触发工厂方法我们看一下getSingleton的逻辑我去掉了无关代码。先从一级缓存中获取如果没有获取到会触发createBean工厂方法的执行 public Object getSingleton(String beanName, ObjectFactory? singletonFactory) {synchronized (this.singletonObjects) {//从一级缓存中获取Object singletonObject this.singletonObjects.get(beanName);if (singletonObject null) {//一级缓存不存在,执行工厂方法创建beansingletonObject singletonFactory.getObject();newSingleton true;//bean创建成功,放入一级缓存if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}}//将创建完成的对象放入一级缓存中也就是单例池中protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}从上面的逻辑我们可以得到一个结论一级缓存的bean已经是创建完成的bean可以对外提供服务。 接下来我们继续看工厂方法createBean的流程创建bean的流程在AbstractAutowireCapableBeanFactory的doCreateBean方法中我去掉了无关逻辑。 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Nullable Object[] args)throws BeanCreationException {//初始化bean,相当于new对象操作if (instanceWrapper null) {instanceWrapper createBeanInstance(beanName, mbd, args);}boolean earlySingletonExposure (mbd.isSingleton() this.allowCircularReferences isSingletonCurrentlyInCreation(beanName));//Spring解决循环依赖的核心逻辑if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace(Eagerly caching bean beanName to allow for resolving potential circular references);}//放入三级缓存addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject bean;//对当前bean进行依赖注入populateBean(beanName, mbd, instanceWrapper);//初始化bean,执行bean的一些初始化方法,比如各种aware、实现各种接口啥的。这个流程也有一个经典的面试题,bean的生命周期exposedObject initializeBean(beanName, exposedObject, mbd);return exposedObject;}上面就是创建A的具体逻辑我们画个图梳理一下 创建A的流程中可以看到在实例化A之后就执行了放入三级缓存的动作。只要你没有禁止循环依赖刚实例化的bean就会放入三级缓存。 protected void addSingletonFactory(String beanName, ObjectFactory? singletonFactory) {Assert.notNull(singletonFactory, Singleton factory must not be null);synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}添加进三级缓存的是一个lambda表达式() - getEarlyBeanReference(beanName, mbd, bean)我们经常叫做工厂那这个工厂方法又是什么时候触发呢?先按下不表我们继续往下看A进入三级缓存后逻辑紧接着就要对A进行依赖注入A需要依赖注入B此时要去容器中获取B获取B的流程和获取A的流程是一样的获取入口也是AbstractBeanFactory的doGetBean方法和获取A一样也执行一遍三级缓存的获取操作就是getSingleton方法。当然也是没有所以需要创建B。 创建B的过程和创建A的过程一样。 实例化—依赖注入—初始化 我们把B的创建流程也画一下 B的依赖注入需要注入A我们需要先获取A此时就又会走到AbstractBeanFactory的doGetBean的逻辑中。又会执行getSingleton逻辑。 protected Object getSingleton(String beanName, boolean allowEarlyReference) {//先从一级缓存取Object singletonObject this.singletonObjects.get(beanName);if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {//一级缓存没有,从二级缓存取singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null allowEarlyReference) {//二级缓存没有,从三级缓存取ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {singletonObject singletonFactory.getObject();//三级缓存取出来之后放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);//从三级缓存移除this.singletonFactories.remove(beanName);}}}}return singletonObject;}一级缓存还是没有二级缓存也没有但是三级此时就有了因为我们创建A的过程中已经把A先放入了三级缓存。此时从三级缓存中获取出来的工厂方法 “() - getEarlyBeanReference(beanName, mbd, bean)” 就会触发拿到A然后将A放入二级缓存。我们看下这个工厂方法的逻辑里都干了啥 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;}以上代码等价于 Object exposedObject bean; exposedObject beanPostProcessor.getEarlyBeanReference(exposedObject, beanName); return exposedObject;processor虽然是一个集合但是真正起作用的processor只有一个就是AnnotationAwareAspectJAutoProxyCreator它是通过EnableAspectJAutoProxy注解导入到bean容器中的从名字也能看到它是处理AOP的。我们看看这个processor的处理逻辑 Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);//获取AOP代理对象return wrapIfNecessary(bean, beanName, cacheKey);}实际上就是AOP代理的增强过程 但是我们的业务代码不一定都会用到AOP吧。那如果不用AOP的话容器中就不会有AnnotationAwareAspectJAutoProxyCreator对象那getEarlyBeanReference方法就可以简化为 Object exposedObject bean; return exposedObject;相当于工厂方法啥也没干。所以这就是为啥Spring放入三级缓存的是一个工厂方法而不是立即获取代理对象放入三级缓存因为在创建A的过程中并不一定存在循环依赖如果没有循环依赖Spring处理AOP增强的逻辑统一在bean创建流程的末尾就是initializeBean方法中 //对当前bean进行依赖注入populateBean(beanName, mbd, instanceWrapper);//初始化bean,执行bean的一些初始化方法,比如各种aware、实现各种接口啥的。这个流程也有一个经典的面试题,bean的生命周期exposedObject initializeBean(beanName, exposedObject, mbd);就是因为Spring也不确认依赖注入过程中是否会有循环依赖它没办法只能先暴露一个工厂方法等到循环依赖真正产生的时候再执行工厂方法相当于把AOP增强过程延迟了。 至此我们小结一下我们完善一下创建A的流程 此时我们就拿到了A虽然不完美但是已经可以让B的创建流程继续往下走B创建完成后将B放入单例池。然后继续创建A。A完成放入单例池结束。Spring的循环依赖就是这样解决的。 下面我们说2个经典的面试题 1、为什么需要三级缓存二级缓存可以吗 不但不可以而且可能会破坏Spring的整体设计。我们说2种情况。 A是一个AOP对象对A进行依赖注入前Spring也不知道会不会存在循环依赖只能先把A进行AOP增强放入二级缓存这样做明显是不合理的如果后面不存在循环依赖我们提前搞了一个代理对象就做了无用功并且也破坏了Spring的整体设计因为Spring会在bean创建的末尾统一进行AOP增强提前搞没有任何意义。有的同学会说工厂方法确实有必要存在那二级缓存有必要吗我只保留一级和三级不要二级可以吗?那就是下面这道面试题了。 2、只有一级和三级没有二级可以吗 猛地一看二级缓存确实啥也没干就是存取对象真实的情况是这样吗肯定不是的。抛开代码不说就凭Spring的使用范围如此之广不可能出现一段无用代码。那二级缓存的作用是什么呢我举一个例子你马上就明白了。下面这种场景二级缓存必须得有。 A依赖BB依赖A(三级缓存中获取A将A加入二级缓存)B依赖CC依赖A(二级缓存中获取A)如果没有二级缓存那我们需要执行两次A的三级缓存工厂方法如果依赖关系更复杂可能需要执行多次工厂方法显然是不合理的所以Spring的二级缓存很重要。 我们画一下以上循环依赖的处理过程 我标注了序号你可以按照序号来看一下整个过程然后自己debug一遍代码对二级缓存存在的必要会有一个更清洗的认识 我们总结一下Spring三级缓存的作用。 第一级缓存存放完整的bean对象这里面的bean已经可以对外提供服务 第二级缓存已经进行了实例化但是未完成依赖注入和初始化的对象 第三级缓存存放工厂方法。提前暴露的一个对象Spring解决循环依赖的核心所在
http://www.dnsts.com.cn/news/274389.html

相关文章:

  • 在企业网站建设的解决方案中深圳培训公司网站建设
  • 网站建设更新维护工作免费ai写作网站
  • 军棋是哪个网站开发的确定网站开发团队
  • 农业信息网站建设意义找外国女朋友的网站建设
  • 电子商务网站建设与管理a网站设计主要包括哪些步骤
  • 百度网站分析报告上海企业网站建设电话
  • 我的世界服务器网站怎么做wordpress 后台相册管理
  • 上海网站建设公司电福利博客wordpress主题
  • 做移动互联网站点重庆观音桥简介
  • 中亿丰建设集团股份有限公司官方网站渠道网创业加盟博览会
  • wordpress 基础建站系统搭建
  • h5网站开发公司wordpress定时函数
  • wordpress 消息框天津seo技术教程
  • dede关闭网站wordpress js特效
  • 做网站蓝色和什么颜色搭配好看海口网站建设解决方案
  • 如何给网站做右侧悬浮电话个人网页设计尺寸
  • 深圳住房和建设局网站网上申请万网域名查询网
  • php第一季网站开发实例教程网站的技术维护一般要做些什么
  • 服务好 售后好的网站制作集团网站建设案例与网站作用
  • 江都建设集团有限公司官方网站网站开发自学还是培训
  • 昆山网站制作哪家强网站的外链接数
  • 广州网站建设海珠新科百度seo规则最新
  • 湖北省住房和城乡建设厅网站网站自定义title
  • 建站超市安卓系统
  • 网站开发合同技术目标免费发布推广的网站
  • 南京网站制作工具网站链接
  • 抖音里做我女朋友网站宁波广告牌制作公司
  • 网站开发是什么经营范围抖音推广网站
  • 网站如何做图片特效西安专业网站制作服务
  • 阳春市建设局网站中山网站建设文化市场