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

网站开发上海网站建设方案书备案设计图

网站开发上海,网站建设方案书备案设计图,宁波网站关键词推广,黄岛网站建设负面消息处理一、背景 在最近的业务需求开发过程中遇到了“传说中”的循环依赖问题#xff0c;在之前学习Spring的时候经常会看到Spring是如何解决循环依赖问题的#xff0c;所谓循环依赖即形成了一个环状的依赖关系#xff0c;这个环中的某一个点产生不稳定变化都会导致整个链路产生不…一、背景 在最近的业务需求开发过程中遇到了“传说中”的循环依赖问题在之前学习Spring的时候经常会看到Spring是如何解决循环依赖问题的所谓循环依赖即形成了一个环状的依赖关系这个环中的某一个点产生不稳定变化都会导致整个链路产生不稳定的变化此外循环依赖还会导致应用程序启动失败、内存溢出、甚至出现一些难以排查的问题于是便系统性的对该问题进行学习和总结并整理文章如下。 二.、循环依赖 2.1. 什么是循环依赖 循环依赖指的是多个对象之间的依赖关系形成了一个闭环。图1、2分别是两个对象和多个对象形成循环依赖图示实际编程中由于依赖层次深、关系复杂等因素导致依赖关系难以清晰梳理。 图1两个对象间的循环依赖 图2多个对象间的循环依赖 2.2. 为什么会产生循环依赖 Spring创建bean的本质还是创建对象一个完整的对象包含两部分当前对象的实例化和对象属性的实例化。在Spring中对象的实例化是通过反射实现的而对象的属性则是在对象实例化之后通过一定的方式设置的。 图3Spring创建Bean流程 接下来以Demo中的类A、B为例描述循环依赖产生过程 Demo中的类A、B中各自都以对方为自己的全局属性并且在Spring中实例化bean是通过ApplicationContext.getBean()方法来进行的。 如果获取的对象依赖了另一个对象那么会首先创建当前对象然后通过递归的调用ApplicationContext.getBean()方法来获取所依赖的对象最后将获取到的对象注入到当前对象中。 Component public class A {private B b;public void setB(B b) {this.b b;} } Component public class B {private A a;public void setA(A a) {this.a a;} }此处以Demo中初始化A对象为例 第一步首先Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例由于Spring容器中还没有A对象实例因而其会创建一个A对象然后发现其依赖了B对象所以会尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例但是Spring容器中此时也没有B对象的实例因而其还是会先创建一个B对象的实例。 此时A对象和B对象都已经创建了并且保存在Spring容器中了只不过A对象的属性b和B对象的属性a都还没有设置进去。 第二步在前面Spring创建B对象之后Spring发现B对象依赖了属性a因而此时还是会尝试递归的调用ApplicationContext.getBean()方法获取A对象的实例因为Spring中已经有一个A对象的实例虽然只是半成品其属性b还未初始化但其也还是目标bean因而会将该A对象的实例返回。此时B对象的属性a就设置进去了然后还是ApplicationContext.getBean()方法递归的返回也就是将B对象的实例返回此时就会将该实例设置到A对象的属性b中。 第三步在上面这个递归过程的最后Spring将获取到的B对象实例设置到了A对象的属性b中了这里的A对象其实和前面设置到实例B中的半成品A对象是同一个对象其引用地址是同一个这里为A对象的b属性设置了值其实也就是为那个半成品的a属性设置了值。 实际加载过程流程图如图4所示其中图中getBean()表示调用Spring的ApplicationContext.getBean()方法而该方法中的参数则表示我们要尝试获取的目标对象。图中的黑色箭头表示一开始的方法调用走向走到最后返回了Spring中缓存的A对象之后表示递归调用返回了此时使用红色的箭头表示。从图中我们可以很清楚的看到B对象的a属性是在第三步中注入的半成品A对象而A对象的b属性是在第二步中注入的成品B对象此时半成品的A对象也就变成了成品的A对象因为其属性已经设置完成了。 图4Bean加载流程图 三、Spring缓存机制 3.1. Spring是如何解决循环依赖的 Spring在DefaultSingletonBeanRegistry类中维护了三个Map也就是我们通常说的三级缓存。 singletonObjects 一级缓存 它是我们最熟悉的朋友俗称“单例池”“容器”缓存创建完成单例Bean的地方。 earlySingletonObjects二级缓存 映射Bean的早期引用也就是说在这个Map里的Bean不是完整的甚至还不能称之为“Bean”只是一个Instance。 singletonFactories三级缓存 映射创建Bean的原始工厂。 图5Spring三级缓存 3.2. Spring源码之“获取Bean 接下来结合具体的Spring源码进行分析首先分析“获取Bean”的源码注意getSingleton()方法。 public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {//第1级缓存 用于存放 已经属性赋值、完成初始化的 单例Beanprivate final MapString, Object singletonObjects new ConcurrentHashMap(256);//第2级缓存 用于存在已经实例化还未做代理属性赋值操作的 单例Beanprivate final MapString, Object earlySingletonObjects new HashMap(16);//第3级缓存 存储创建单例Bean的工厂private final MapString, ObjectFactory? singletonFactories new HashMap(16);//已经注册的单例池里的beanNameprivate final SetString registeredSingletons new LinkedHashSet(256);//正在创建中的beanName集合private final SetString singletonsCurrentlyInCreation Collections.newSetFromMap(new ConcurrentHashMap(16));//缓存查找bean 如果第1级缓存没有那么从第2级缓存获取。如果第2级缓存也没有那么从第3级缓存创建并放入第2级缓存。protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject this.singletonObjects.get(beanName); //第1级if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject this.earlySingletonObjects.get(beanName); //第2级if (singletonObject null allowEarlyReference) {//第3级缓存 在doCreateBean中创建了bean的实例后封装ObjectFactory放入缓存的bean实例ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {//创建未赋值的beansingletonObject singletonFactory.getObject();//放入到第2级缓存this.earlySingletonObjects.put(beanName, singletonObject);//从第3级缓存删除this.singletonFactories.remove(beanName);}}}}return singletonObject;} }3.3. Spring源码之“添加到第1级缓存” 其中“添加到第1级缓存”的源码为 protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {// 放入第1级缓存this.singletonObjects.put(beanName, singletonObject);// 从第3级缓存删除this.singletonFactories.remove(beanName);// 从第2级缓存删除this.earlySingletonObjects.remove(beanName);// 放入已注册的单例池里this.registeredSingletons.add(beanName);}}添加到“第3级缓存”的源码为 protected void addSingletonFactory(String beanName, ObjectFactory? singletonFactory) {synchronized (this.singletonObjects) {// 若第1级缓存没有bean实例if (!this.singletonObjects.containsKey(beanName)) {// 放入第3级缓存this.singletonFactories.put(beanName, singletonFactory);// 从第2级缓存删除确保第2级缓存没有该beanthis.earlySingletonObjects.remove(beanName);// 放入已注册的单例池里this.registeredSingletons.add(beanName);}}}“创建Bean”的源码为下面所示通过这段代码我们可以知道Spring 在实例化对象之后就会为其创建一个 Bean 工厂并将此工厂加入到三级缓存中。 因此Spring 一开始提前暴露的并不是实例化的 Bean而是将 Bean 包装起来的ObjectFactory。为什么要这么做呢 这实际上涉及到 AOP。如果创建的 Bean 是有代理的那么注入的就应该是代理 Bean而不是原始的 Bean。但是Spring一开始并不知道 Bean是否会有循环依赖通常情况下没有循环依赖的情况下Spring 都会在“完成填充属性并且执行完初始化方法”之后再为其创建代理。但是如果出现了循环依赖Spring 就不得不为其提前创建代理对象否则注入的就是一个原始对象而不是代理对象。因此这里就涉及到应该在哪里提前创建代理对象。 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {BeanWrapper instanceWrapper null;if (instanceWrapper null) {//实例化对象instanceWrapper this.createBeanInstance(beanName, mbd, args);}final Object bean instanceWrapper ! null ? instanceWrapper.getWrappedInstance() : null;Class? beanType instanceWrapper ! null ? instanceWrapper.getWrappedClass() : null;//判断是否允许提前暴露对象如果允许则直接添加一个 ObjectFactory 到第3级缓存boolean earlySingletonExposure (mbd.isSingleton() this.allowCircularReferences isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {//添加到第3级缓存addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean));}//填充属性this.populateBean(beanName, mbd, instanceWrapper);//执行初始化方法并创建代理exposedObject initializeBean(beanName, exposedObject, mbd);return exposedObject; }Spring通过在ObjectFactory中去提前创建代理对象该对象会执行getObject()方法来获取Bean。执行方法如下 public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);// 记录已被代理的对象this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);} }提前进行对象的代理工作并在 earlyProxyReferences map中记录已被代理的对象是为了避免在后面重复创建代理对象。 public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);// 记录已被代理的对象this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);} }再次分析获取bean的方法getSingleton()方法可知提前暴露的对象虽然已实例化但是没有进行属性填充还没有完成初始化是一个不完整的对象。 这个对象存放在二级缓存中对于三级缓存机制十分重要是解决循环依赖一个非常巧妙的设计。接下来我们结合Spring缓存机制来分析上面Demo中A、B循环依赖。 A 调用doCreateBean()创建Bean对象由于还未创建从第1级缓存singletonObjects查不到此时只是一个半成品提前暴露的对象放入第3级缓存singletonFactories。 A在属性填充时发现自己需要B对象但是在三级缓存中均未发现B于是创建B的半成品放入第3级缓存singletonFactories。 B在属性填充时发现自己需要A对象从第1级缓存singletonObjects和第2级缓存earlySingletonObjects中未发现A但是在第3级缓存singletonFactories中发现A将A放入第2级缓存earlySingletonObjects同时从第3级缓存singletonFactories删除。 将A注入到对象B中。 B完成属性填充执行初始化方法将自己放入第1级缓存singletonObjects中此时B是一个完整的对象同时从第3级缓存singletonFactories和第2级缓存earlySingletonObjects中删除。 A得到“对象B的完整实例”将B注入到A中。 A完成属性填充执行初始化方法并放入到第1级缓存singletonObjects中。 在创建过程中都是从第三级缓存(对象工厂创建不完整对象)将提前暴露的对象放入到第二级缓存从第二级缓存拿到后完成初始化并放入第一级缓存。
http://www.sadfv.cn/news/47488/

相关文章:

  • 广告网站设计公司旅游网站排行榜前20
  • 建筑工程的公司网站优化怎样提高网站用户体验
  • namecheap建站wordpress优化型网站模板
  • 郴州网站建设软件定制开发平台wordpress自定义字段面板
  • wordpress能做多大的站镇江网签查询系统
  • 沧州建设银行招聘网站网站建设一百万
  • 网站建设设城固县网站建设
  • 烟台工程建设信息网站南昌seo推广公司
  • 网站建设技术方面的论文个人电脑搭建云服务器
  • 肇庆市网站建设平台电子商务以后能干什么
  • 做装修那个网站好济南智能网站建设报价
  • 在淘宝介绍里边怎么做网站链接邢台旅游景点大全排名 免费
  • 网络销售怎么一直招人漳州做网站优化
  • 网站建设教程 迅雷下载关于建设旅游网站的书籍
  • 手机网站模板 餐饮遂宁住房和城乡建设厅网站
  • 营销型网站用什么系统西安摩高网站建设
  • 柳州建站小程序开发者工具下载
  • 手机网站源码带后台眉山网站推广
  • 安阳做推广网站兼职做彩平网站
  • 仿阿里巴巴行业门户贸易网站模板长沙产品设计公司
  • 牙科医院网站开发网站可以自己做吗
  • 天津网站优化哪家快建设公司大还是建筑公司大
  • 设计网站注意哪些问题网站创建软件
  • 绘本馆网站建设163建筑网站
  • name域名的网站工业部网站备案
  • 网站建设服务协议 印花税网络公司门头
  • 徐州建站公司哪家好一键优化内存
  • 为代理网站做网站做网站申请完域名后做什么
  • 做网课网站wordpress 增加子目录
  • 网站建设优化现状图表长春制作网站哪家好