范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

不要再问Spring是如何解决循环依赖了

  1、什么是循环依赖?
  循环依赖主要来次三个方面,第一种A相互依赖,第二种是 A依赖B,B依赖A,第三种是A依赖B,B依赖C,C依赖A。
  总结一句话就是对象之间形成环形依赖。
  代码如下:
  第一种:public class A {     private A a; }
  第二种:public class A {     private B b; } class B {     private A a; }
  第三种:public class A {     private B b; } class B {     private C c; } class C {     private A a; } 2、Spring 三级缓存是什么?第一级缓存:singletonObjects,用于缓存成品的bean,保证 Spring 的单例属性。第二级缓存:earlySingletonObjects,用于保存实例化完成的半成品 bean 实例,包括AOP代理对象。第三级缓存:singletonFactories,Map>,Map 的 Value 是一个对象的代理工厂,用来存放对象的代理工厂用于保存 bean 创建工厂,以便后面有机会创建代理对象。为"打破循环"而生,存放的是生成半成品单例 Bean 的工厂方法。
  要想说清楚三级缓存,我们先来看Spring bean 的生命周期,看bean的创建过程。
  核心几个类我们从AnnotationConfigApplicationContext上下文为基础来讲解bean的生命周期,AnnotationConfigApplicationContext是基于注解的上下文,看下这核心构造器。 	/** 	 * Create a new AnnotationConfigApplicationContext, deriving bean definitions 	 * from the given component classes and automatically refreshing the context. 	 * @param componentClasses one or more component classes — for example, 	 * {@link Configuration @Configuration} classes 	 */ 	public AnnotationConfigApplicationContext(Class<?>... componentClasses) { 		this(); 		register(componentClasses); 		refresh(); 	}
  再看refresh()public void refresh() throws BeansException, IllegalStateException { 		synchronized (this.startupShutdownMonitor) { 			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");  			// Prepare this context for refreshing. 			prepareRefresh();  			// Tell the subclass to refresh the internal bean factory. 			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  			// Prepare the bean factory for use in this context. 			prepareBeanFactory(beanFactory);  			try { 				// Allows post-processing of the bean factory in context subclasses. 				postProcessBeanFactory(beanFactory);  				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); 				// Invoke factory processors registered as beans in the context. 				invokeBeanFactoryPostProcessors(beanFactory);  				// Register bean processors that intercept bean creation. 				registerBeanPostProcessors(beanFactory); 				beanPostProcess.end();  				// Initialize message source for this context. 				initMessageSource();  				// Initialize event multicaster for this context. 				initApplicationEventMulticaster();  				// Initialize other special beans in specific context subclasses. 				onRefresh();  				// Check for listener beans and register them. 				registerListeners();  				// Instantiate all remaining (non-lazy-init) singletons. 				finishBeanFactoryInitialization(beanFactory);  				// Last step: publish corresponding event. 				finishRefresh(); 			}  			catch (BeansException ex) { 				if (logger.isWarnEnabled()) { 					logger.warn("Exception encountered during context initialization - " + 							"cancelling refresh attempt: " + ex); 				}  				// Destroy already created singletons to avoid dangling resources. 				destroyBeans();  				// Reset "active" flag. 				cancelRefresh(ex);  				// Propagate exception to caller. 				throw ex; 			}  			finally { 				// Reset common introspection caches in Spring"s core, since we 				// might not ever need metadata for singleton beans anymore... 				resetCommonCaches(); 				contextRefresh.end(); 			} 		} 	}
  核心主要是finishBeanFactoryInitialization(),其中beanFactory.preInstantiateSingletons()该方法中会生成所有非懒加载的单例bean。 	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { 		// Initialize conversion service for this context. 		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && 				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { 			beanFactory.setConversionService( 					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); 		}  		// Register a default embedded value resolver if no BeanFactoryPostProcessor 		// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before: 		// at this point, primarily for resolution in annotation attribute values. 		if (!beanFactory.hasEmbeddedValueResolver()) { 			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); 		}  		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. 		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); 		for (String weaverAwareName : weaverAwareNames) { 			getBean(weaverAwareName); 		}  		// Stop using the temporary ClassLoader for type matching. 		beanFactory.setTempClassLoader(null);  		// Allow for caching all bean definition metadata, not expecting further changes. 		beanFactory.freezeConfiguration();  		// Instantiate all remaining (non-lazy-init) singletons. 		beanFactory.preInstantiateSingletons(); 	}public void preInstantiateSingletons() throws BeansException {     if (logger.isTraceEnabled()) {     logger.trace("Pre-instantiating singletons in " + this); }  // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List beanNames = new ArrayList<>(this.beanDefinitionNames);  // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) {     RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);     if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {         if (isFactoryBean(beanName)) {             Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);             if (bean instanceof FactoryBean) {                 FactoryBean<?> factory = (FactoryBean<?>) bean;                 boolean isEagerInit;                 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {                     isEagerInit = AccessController.doPrivileged(                         (PrivilegedAction) ((SmartFactoryBean<?>) factory)::isEagerInit,                         getAccessControlContext());                 }                 else {                     isEagerInit = (factory instanceof SmartFactoryBean &&                                    ((SmartFactoryBean<?>) factory).isEagerInit());                 }                 if (isEagerInit) {                     getBean(beanName);                 }             }         }         else {             getBean(beanName);         }     } }  // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) {     Object singletonInstance = getSingleton(beanName);     if (singletonInstance instanceof SmartInitializingSingleton) {         StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")             .tag("beanName", beanName);         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;         if (System.getSecurityManager() != null) {             AccessController.doPrivileged((PrivilegedAction) () -> {                 smartSingleton.afterSingletonsInstantiated();                 return null;             }, getAccessControlContext());         }         else {             smartSingleton.afterSingletonsInstantiated();         }         smartInitialize.end();     } } }
  doGetBean方法中有getSingleton、getObjectForBeanInstance、createBean 比较核心,下面继续看下这代码。代码篇幅过长、简单理解下 ,在doGetBean方法中首先调用getSingleton方法检查单例缓存中是否有该bean ,这也是我们分析三级缓存的关键,如果没有则判断当前bean的作用域是单例(singleton)还是原型(prototype),如果是单例的,再次调用getSingleton方法,不过这次的该方法是重载的一个;如果是原型的则调用createBean方法生成bean,上面几个步骤生成的beanInstance均要调用getObjectForBeanInstance方法获得bean对象。 protected  T doGetBean( 			String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) 			throws BeansException {  		String beanName = transformedBeanName(name); 		Object beanInstance;  		// Eagerly check singleton cache for manually registered singletons. 		Object sharedInstance = getSingleton(beanName); 		if (sharedInstance != null && args == null) { 			if (logger.isTraceEnabled()) { 				if (isSingletonCurrentlyInCreation(beanName)) { 					logger.trace("Returning eagerly cached instance of singleton bean "" + beanName + 							"" that is not fully initialized yet - a consequence of a circular reference"); 				} 				else { 					logger.trace("Returning cached instance of singleton bean "" + beanName + """); 				} 			} 			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); 		}  		else { 			// Fail if we"re already creating this bean instance: 			// We"re assumably within a circular reference. 			if (isPrototypeCurrentlyInCreation(beanName)) { 				throw new BeanCurrentlyInCreationException(beanName); 			}  			// Check if bean definition exists in this factory. 			BeanFactory parentBeanFactory = getParentBeanFactory(); 			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 				// Not found -> check parent. 				String nameToLookup = originalBeanName(name); 				if (parentBeanFactory instanceof AbstractBeanFactory) { 					return ((AbstractBeanFactory) parentBeanFactory).doGetBean( 							nameToLookup, requiredType, args, typeCheckOnly); 				} 				else if (args != null) { 					// Delegation to parent with explicit args. 					return (T) parentBeanFactory.getBean(nameToLookup, args); 				} 				else if (requiredType != null) { 					// No args -> delegate to standard getBean method. 					return parentBeanFactory.getBean(nameToLookup, requiredType); 				} 				else { 					return (T) parentBeanFactory.getBean(nameToLookup); 				} 			}  			if (!typeCheckOnly) { 				markBeanAsCreated(beanName); 			}  			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") 					.tag("beanName", name); 			try { 				if (requiredType != null) { 					beanCreation.tag("beanType", requiredType::toString); 				} 				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 				checkMergedBeanDefinition(mbd, beanName, args);  				// Guarantee initialization of beans that the current bean depends on. 				String[] dependsOn = mbd.getDependsOn(); 				if (dependsOn != null) { 					for (String dep : dependsOn) { 						if (isDependent(beanName, dep)) { 							throw new BeanCreationException(mbd.getResourceDescription(), beanName, 									"Circular depends-on relationship between "" + beanName + "" and "" + dep + """); 						} 						registerDependentBean(dep, beanName); 						try { 							getBean(dep); 						} 						catch (NoSuchBeanDefinitionException ex) { 							throw new BeanCreationException(mbd.getResourceDescription(), beanName, 									""" + beanName + "" depends on missing bean "" + dep + """, ex); 						} 					} 				}  				// Create bean instance. 				if (mbd.isSingleton()) { 					sharedInstance = getSingleton(beanName, () -> { 						try { 							return createBean(beanName, mbd, args); 						} 						catch (BeansException ex) { 							// Explicitly remove instance from singleton cache: It might have been put there 							// eagerly by the creation process, to allow for circular reference resolution. 							// Also remove any beans that received a temporary reference to the bean. 							destroySingleton(beanName); 							throw ex; 						} 					}); 					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 				}  				else if (mbd.isPrototype()) { 					// It"s a prototype -> create a new instance. 					Object prototypeInstance = null; 					try { 						beforePrototypeCreation(beanName); 						prototypeInstance = createBean(beanName, mbd, args); 					} 					finally { 						afterPrototypeCreation(beanName); 					} 					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 				}  				else { 					String scopeName = mbd.getScope(); 					if (!StringUtils.hasLength(scopeName)) { 						throw new IllegalStateException("No scope name defined for bean "" + beanName + """); 					} 					Scope scope = this.scopes.get(scopeName); 					if (scope == null) { 						throw new IllegalStateException("No Scope registered for scope name "" + scopeName + """); 					} 					try { 						Object scopedInstance = scope.get(beanName, () -> { 							beforePrototypeCreation(beanName); 							try { 								return createBean(beanName, mbd, args); 							} 							finally { 								afterPrototypeCreation(beanName); 							} 						}); 						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 					} 					catch (IllegalStateException ex) { 						throw new ScopeNotActiveException(beanName, scopeName, ex); 					} 				} 			} 			catch (BeansException ex) { 				beanCreation.tag("exception", ex.getClass().toString()); 				beanCreation.tag("message", String.valueOf(ex.getMessage())); 				cleanupAfterBeanCreationFailure(beanName); 				throw ex; 			} 			finally { 				beanCreation.end(); 			} 		}  		return adaptBeanInstance(name, beanInstance, requiredType); 	}
  我们知道了DefaultSingletonBeanRegistry类下的getSingleton是Spring bean 缓存的关键,那么看下代码, 	/** 	 * Return the (raw) singleton object registered under the given name. 	 * 

Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ @Nullable 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; }   以上就是从源码上了解三级缓存,执行流程:1.先从"第一级缓存"找对象,有就返回,没有就找"二级缓存";   2.找"二级缓存",有就返回,没有就找"三级缓存";   3.找"三级缓存",找到了,就获取对象,放到"二级缓存",从"三级缓存"移除。3、如何解决缓存依赖问题?   以上都是Spring 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)) { // 直接从工厂中获取 Bean object o = singletonFactory.getObject(); // 添加至二级缓存中 this.earlySingletonObjects.put(beanName, o); this.registeredSingletons.add(beanName); } } }   总结来说,Spring 通过三级缓存实现循环依赖,来存放对象的代理工厂用于保存 bean 创建工厂。在遇到循环依赖时候优先通过二级缓存看是否存在依赖对象的半成品、没有则去三级缓存获取Bean Factory创建对象,创建成功之后放入到二级缓存中。   为什么多出二级缓存呢,只要三级缓存能不能实现?   二级缓存"的目的是为了避免因为 AOP 创建多个对象,其中存储的是半成品的 AOP 的单例 bean。   能不能只要二级缓存,二级缓存也可以解决循环依赖问题啊?   主要解决代理对象问题,假如不存在代理对象,二级缓存也是足够的。   Spring 只用二级缓存来解决循环依赖,那么所有 Bean 都需要在实例化完成之后就立马为其创建代理,而Spring 的设计原则是会在完成属性填充、并且执行完初始化之后再为其创建代理 。所以,Spring 选择了三级缓存,,但是因为循环依赖的出现,导致了 Spring 不得不提前去创建代理,因为如果不提前创建代理对象,那么注入的就是原始对象,这样就会产生错误。


全家都爱吃的面包,不用揉面,不用出膜,出炉柔软又拉丝,太香了面包我们都爱吃,它跟我们的包子馒头差不多,都有发酵食物,但一个是烤出来的一个是蒸出来的。面粉是用高筋面粉做的,且水量很大,所以会更柔软,我们经常会用拉丝效果来评论这个面包好不好。面猪肝上锅蒸一蒸,想不到这么好吃,饭店里从没吃过,太意外了大部分朋友不太喜欢吃猪肝,因为猪肝吃起来有一股腥味,而且口感也并不算很好。但是如果猪肝处理得比较好,那么做出来的美食是特别美味的,就比如说今天要跟大家分享的这道杏鲍菇蒸猪肝。猪肝经北京希望在线猿辅导等5家中小学线上营转非获审批,双减重剑下的独辟蹊径作者王起端编辑二维马雷峰网消息,12月13日,据中国社会组织政务服务平台,北京市已审批5家中小学学科培训非营利机构。据了解,这5家机构分别为北京希望在线线上学科培训学校北京猿辅导线网游中的生活帮该不该活着?玩家这些人吃资源活跃,打架又怂着在网络游戏中,胜者为王,败者为寇是一条恒久不变的定律,特别是在宏大的武侠世界里,强者为尊更是无可争议的铁律。很多玩家在玩网游的时候,总喜欢加入那些强势的战斗帮,通过野外厮杀来一点点2021最好看的韩剧鱿鱼游戏当贫民进入现代罗马竞技场爽由于反乌托邦的电影题材已数不胜数,剧情要如何玩出新滋味则成了脱颖而出的关键。在鱿鱼游戏中,我认为它的特别之处即是致力创造角色背景的多样性,借以洞察社会底层的不同身份,如何运用自己的周琦在NBL呼风唤雨!这3位国内顶尖内线同样有机会在澳洲站稳脚跟最近刚刚从CBA转投至澳洲NBL墨尔本凤凰队的周琦,刚刚打出了加盟这支全新联赛的最佳一战,在对战墨尔本联的比赛中交出22分10篮板7盖帽的准三双。看得出来咱们国内的顶尖大个子在去到婴幼儿能不能看电视?父母不妨照着国内外的研究成果做,错不了对于婴幼儿能不能看电视,很多家长都持有不同的态度,你是什么态度呢?姗姗在有娃之后,对于不让宝宝看电视这件事存在否定态度,姗姗觉得,现在是信息时代,孩子怎么可能不去接触电视呢?所以,导游提醒跟团游最好做到四不要,旅游体验会更好现在旅游已经成了人们生活中不可缺少的一部分,每到节假日,国内外许多景点都挤满了人,很多人外出旅游的时候会选择自由行,尤其是国内游,不存在语言的问题,带上东西,买张火车票就可以来一段IUWE感情升温圣地,在浪漫的旅行中看遍最美的风景旅行,最试验得出一个人的品性。舟车劳顿后,双方还没有彼此看厌没有拌嘴翻脸,这种感情才经得起日后考验。钱钟书围城旅途的劳顿疲惫与麻烦最是让人本相毕现,因此旅行也成了众多情侣之间考验爱黄圣依24岁嫁入豪门,被婆婆宠成公主,与继女情同手足2004年,一部动作喜剧类电影功夫横空出世。黄圣依凭借着哑女芳儿一角一炮而红,获得大众电影百花奖最佳新人奖。随后,她参演了天仙配白蛇传说新九品芝麻官碧血剑爱情呼叫转移等精彩作品。她演员哭戏的对比中,什么叫演技,什么叫尴尬,一目了然娱乐圈里面有许多形形色色的演员,他们有的演技扎实,业务能力精湛有的却浑浑噩噩,妄想鱼目混珠过去。但是群众的眼睛却是雪亮的,谁真谁假,一眼便可以看穿。下面,我们就从几场演员哭戏的巅峰
杜锋喜上加喜,CBA八冠王成功留队,帮助广东男篮强势冲击总冠军杜锋喜上加喜,CBA八冠王成功留队,帮助广东男篮强势冲击总冠军。CBA联赛在这个夏天发生了不小的变化,各支球队的主教练先后易主,一些小有名气的球员也最终实现了转会。而与此同时一些正这是谁家的新娘?皇马球员动态汇总0625恭喜卡瓦哈尔夫妇,卡2这是属于晚婚晚育了吧?先上卡嫂美图!婚礼发型师发的新娘造型婚礼现场和晚宴的官图估计要过两天才出来,敬请期待!前来祝贺的队友们库尔图瓦和米歇尔米歇尔这身太好看了5年2。48亿!又一个顶薪!签下放弃争冠事情大概是这样,两天前,据HoopsHype记者MichaelScotto报道,奇才球星比尔已经拒绝了下赛季价值3640万美元的球员选项,他将成为完全自由球员,并且有资格和奇才签下泪目!瓦妮莎带3个女儿参观科比旧宅,娜塔莉亚晒与爸爸珍贵合影正值父亲节,不少人发朋友圈来表达自己对父亲的感恩之情,明星也不例外,网友发现瓦妮莎的大女儿娜塔莉亚在INS上传了自己与父亲科比的旧照,照片里的娜娜十分年幼,身着连衣裙站在玩手机的科休赛期恐任人摆布的八大球星,乐福朝不保夕,威少沃尔难兄难弟NBA作为篮球顶级殿堂,从来不缺少超级巨星,在小球盛行的时代,更是众星云集星光璀璨,但,有些球星为了生计,亦或者个人的梦想,牺牲数据,甚至牺牲未来前途的球星也是不计其数,以至于状态梅西被国际足联认证为球王,盘点顶级球员的丑闻事件FIFA官博祝梅西生日独一无二的梅西,请继续骄傲地前行。FIFA的祝福印证了梅西的伟大!确定了梅西的地位!也证明了我们梅粉的眼光,自从梅西出道我就认定他是最好的,到现在从没动摇过,日本一姐空欢喜一场,国际乒联正式官宣,国乒4主力围剿伊藤美诚众所周知,在刚刚结束的WTT克罗地亚分站赛的比赛当中,日本女单选手伊藤美诚成为了最大的赢家。先后拿下了两个冠军之后,伊藤美诚的世界积分有了大幅度的提升,排名也反超了自己的队友早田希国际博物馆日丨带你云游全球趣味十足的博物馆来源央视新闻客户端比利时布鲁塞尔火车世界博物馆,在这里可以看到比利时铁路发展史中最漂亮最独特的火车。瑞典斯德哥尔摩瓦萨沉船博物馆,此馆专为展览一艘从海底打捞上来的瓦萨号沉船而建立。你幸福吗?不丹将全面向国际旅客开放,无需隔离一个比西藏还西藏的地方,雷龙之地,无疑是世界上最不寻常的国家之一。不丹是一块充满神话和传说的土地。不丹以前的隔离规定是14天的强制隔离,目前已降至5天。但旅游业认为,5天的隔离仍会那些一看就挺高级的女人,夏天都爱穿这条醋酸裙,优雅又显贵女人的高级感从来都不是用金钱去衡量的,就好比有人穿在昂贵奢侈的衣服,但是却不适合自己,照样会显得老土没档次而有的女人,就算是身穿平价的服装,却因为合身显气质,体现出最高贵华丽的效果MarshallWOBURNIII家庭音箱,内置5个喇叭,轻松打造家庭影院音效Marshall马歇尔的吉他音箱自上1962年面世以来便长期获得摇滚乐手的青睐,在Marshall鼎盛时期,有些演唱会甚至清一色全是马歇尔的音箱。这一次,我爱音频网想在这篇文章中跟