您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)Springboot中怎么實(shí)現(xiàn)Spring循環(huán)依賴,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
使用了具有代理特性的BeanPostProcessor
典型的有 事務(wù)注解@Transactional,異步注解@Async等
protected Object doCreateBean( ... ){ ... boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } ... // populateBean這一句特別的關(guān)鍵,它需要給A的屬性賦值,所以此處會(huì)去實(shí)例化B~~ // 而B(niǎo)我們從上可以看到它就是個(gè)普通的Bean(并不需要?jiǎng)?chuàng)建代理對(duì)象),實(shí)例化完成之后,繼續(xù)給他的屬性A賦值,而此時(shí)它會(huì)去拿到A的早期引用 // 也就在此處在給B的屬性a賦值的時(shí)候,會(huì)執(zhí)行到上面放進(jìn)去的Bean A流程中的getEarlyBeanReference()方法 從而拿到A的早期引用~~ // 執(zhí)行A的getEarlyBeanReference()方法的時(shí)候,會(huì)執(zhí)行自動(dòng)代理創(chuàng)建器,但是由于A沒(méi)有標(biāo)注事務(wù),所以最終不會(huì)創(chuàng)建代理,so B合格屬性引用會(huì)是A的**原始對(duì)象** // 需要注意的是:@Async的代理對(duì)象不是在getEarlyBeanReference()中創(chuàng)建的,是在postProcessAfterInitialization創(chuàng)建的代理 // 從這我們也可以看出@Async的代理它默認(rèn)并不支持你去循環(huán)引用,因?yàn)樗](méi)有把代理對(duì)象的早期引用提供出來(lái)~~~(注意這點(diǎn)和自動(dòng)代理創(chuàng)建器的區(qū)別~) // 結(jié)論:此處給A的依賴屬性字段B賦值為了B的實(shí)例(因?yàn)锽不需要?jiǎng)?chuàng)建代理,所以就是原始對(duì)象) // 而此處實(shí)例B里面依賴的A注入的仍舊為Bean A的普通實(shí)例對(duì)象(注意 是原始對(duì)象非代理對(duì)象) 注:此時(shí)exposedObject也依舊為原始對(duì)象 populateBean(beanName, mbd, instanceWrapper); // 標(biāo)注有@Async的Bean的代理對(duì)象在此處會(huì)被生成~~~ 參照類:AsyncAnnotationBeanPostProcessor // 所以此句執(zhí)行完成后 exposedObject就會(huì)是個(gè)代理對(duì)象而非原始對(duì)象了 exposedObject = initializeBean(beanName, exposedObject, mbd); ... // 這里是報(bào)錯(cuò)的重點(diǎn)~~~ if (earlySingletonExposure) { // 上面說(shuō)了A被B循環(huán)依賴進(jìn)去了,所以此時(shí)A是被放進(jìn)了二級(jí)緩存的,所以此處earlySingletonReference 是A的原始對(duì)象的引用 // (這也就解釋了為何我說(shuō):如果A沒(méi)有被循環(huán)依賴,是不會(huì)報(bào)錯(cuò)不會(huì)有問(wèn)題的 因?yàn)槿魶](méi)有循環(huán)依賴earlySingletonReference =null后面就直接return了) Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { // 上面分析了exposedObject 是被@Aysnc代理過(guò)的對(duì)象, 而bean是原始對(duì)象 所以此處不相等 走else邏輯 if (exposedObject == bean) { exposedObject = earlySingletonReference; } // allowRawInjectionDespiteWrapping 標(biāo)注是否允許此Bean的原始類型被注入到其它Bean里面,即使自己最終會(huì)被包裝(代理) // 默認(rèn)是false表示不允許,如果改為true表示允許,就不會(huì)報(bào)錯(cuò)啦。這是我們后面講的決方案的其中一個(gè)方案~~~ // 另外dependentBeanMap記錄著每個(gè)Bean它所依賴的Bean的Map~~~~ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { // 我們的Bean A依賴于B,so此處值為["b"] String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); // 對(duì)所有的依賴進(jìn)行一一檢查~ 比如此處B就會(huì)有問(wèn)題 // “b”它經(jīng)過(guò)removeSingletonIfCreatedForTypeCheckOnly最終返返回false 因?yàn)閍lreadyCreated里面已經(jīng)有它了表示B已經(jīng)完全創(chuàng)建完成了~~~ // 而b都完成了,所以屬性a也賦值完成兒聊 但是B里面引用的a和主流程我這個(gè)A竟然不相等,那肯定就有問(wèn)題(說(shuō)明不是最終的)~~~ // so最終會(huì)被加入到actualDependentBeans里面去,表示A真正的依賴~~~ for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } // 若存在這種真正的依賴,那就報(bào)錯(cuò)了~~~ 則個(gè)異常就是上面看到的異常信息 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 " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } ... }
發(fā)生循環(huán)依賴時(shí)候Object earlySingletonReference = getSingleton(beanName, false);
肯定有值
緩存工廠addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
將給實(shí)例對(duì)象添加SmartInstantiationAwareBeanPostProcessor
AbstractAutoProxyCreator
是SmartInstantiationAwareBeanPostProcessor
的子類,一定記住了,一定記住,SmartInstantiationAwareBeanPostProcessor
的子類很關(guān)鍵?。。。?!
exposedObject = initializeBean(beanName, exposedObject, mbd);
進(jìn)行BeanPostProcessor
后置處理,注意是BeanPostProcessor
?。。。?!
Spring
的循環(huán)依賴被它的三級(jí)緩存給輕易解決了,但是這2個(gè)地方的后置處理帶來(lái)了 循環(huán)依賴的問(wèn)題。
對(duì)比AbstractAdvisorAutoProxyCreator和AsyncAnnotationBeanPostProcessor
由于SmartInstantiationAwareBeanPostProcessor
的子類會(huì)在兩處都會(huì)執(zhí)行后置處理,所以前后都會(huì)相同的對(duì)象引用,不會(huì)發(fā)生循環(huán)依賴問(wèn)題,異步注解就不行了 ,至于為什么?自己看上面的分析,仔細(xì)看哦!
改變加載順序
@Lazy
注解
allowRawInjectionDespiteWrapping
設(shè)置為true
(利用了判斷的那條語(yǔ)句)
別使用相關(guān)的BeanPostProcessor
設(shè)計(jì)到的注解,,哈哈 這不太現(xiàn)實(shí)。
@Lazy
一般含義是懶加載,它只會(huì)作用于BeanDefinition.setLazyInit()
。而此處給它增加了一個(gè)能力:延遲處理(代理處理)
// @since 4.0 出現(xiàn)得挺晚,它支持到了@Lazy 是功能最全的AutowireCandidateResolver public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver { // 這是此類本身唯一做的事,此處精析 // 返回該 lazy proxy 表示延遲初始化,實(shí)現(xiàn)過(guò)程是查看在 @Autowired 注解處是否使用了 @Lazy = true 注解 @Override @Nullable public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) { // 如果isLazy=true 那就返回一個(gè)代理,否則返回null // 相當(dāng)于若標(biāo)注了@Lazy注解,就會(huì)返回一個(gè)代理(當(dāng)然@Lazy注解的value值不能是false) return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null); } // 這個(gè)比較簡(jiǎn)單,@Lazy注解標(biāo)注了就行(value屬性默認(rèn)值是true) // @Lazy支持標(biāo)注在屬性上和方法入?yún)⑸蟸~~ 這里都會(huì)解析 protected boolean isLazy(DependencyDescriptor descriptor) { for (Annotation ann : descriptor.getAnnotations()) { Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class); if (lazy != null && lazy.value()) { return true; } } MethodParameter methodParam = descriptor.getMethodParameter(); if (methodParam != null) { Method method = methodParam.getMethod(); if (method == null || void.class == method.getReturnType()) { Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class); if (lazy != null && lazy.value()) { return true; } } } return false; } // 核心內(nèi)容,是本類的靈魂~~~ protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) { Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory, "BeanFactory needs to be a DefaultListableBeanFactory"); // 這里毫不客氣的使用了面向?qū)崿F(xiàn)類編程,使用了DefaultListableBeanFactory.doResolveDependency()方法~~~ final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory(); //TargetSource 是它實(shí)現(xiàn)懶加載的核心原因,在AOP那一章節(jié)了重點(diǎn)提到過(guò)這個(gè)接口,此處不再敘述 // 它有很多的著名實(shí)現(xiàn)如HotSwappableTargetSource、SingletonTargetSource、LazyInitTargetSource、 //SimpleBeanTargetSource、ThreadLocalTargetSource、PrototypeTargetSource等等非常多 // 此處因?yàn)橹恍枰约河?,所以采用匿名?nèi)部類的方式實(shí)現(xiàn)~~~ 此處最重要是看getTarget方法,它在被使用的時(shí)候(也就是代理對(duì)象真正使用的時(shí)候執(zhí)行~~~) TargetSource ts = new TargetSource() { @Override public Class<?> getTargetClass() { return descriptor.getDependencyType(); } @Override public boolean isStatic() { return false; } // getTarget是調(diào)用代理方法的時(shí)候會(huì)調(diào)用的,所以執(zhí)行每個(gè)代理方法都會(huì)執(zhí)行此方法,這也是為何doResolveDependency // 我個(gè)人認(rèn)為它在效率上,是存在一定的問(wèn)題的~~~所以此處建議盡量少用@Lazy~~~ //不過(guò)效率上應(yīng)該還好,對(duì)比http、序列化反序列化處理,簡(jiǎn)直不值一提 所以還是無(wú)所謂 用吧 @Override public Object getTarget() { Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null); if (target == null) { Class<?> type = getTargetClass(); // 對(duì)多值注入的空值的友好處理(不要用null) if (Map.class == type) { return Collections.emptyMap(); } else if (List.class == type) { return Collections.emptyList(); } else if (Set.class == type || Collection.class == type) { return Collections.emptySet(); } throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(), "Optional dependency not present for lazy injection point"); } return target; } @Override public void releaseTarget(Object target) { } }; // 使用ProxyFactory 給ts生成一個(gè)代理 // 由此可見(jiàn)最終生成的代理對(duì)象的目標(biāo)對(duì)象其實(shí)是TargetSource,而TargetSource的目標(biāo)才是我們業(yè)務(wù)的對(duì)象 ProxyFactory pf = new ProxyFactory(); pf.setTargetSource(ts); Class<?> dependencyType = descriptor.getDependencyType(); // 如果注入的語(yǔ)句是這么寫(xiě)的private AInterface a; 那這類就是借口 值是true // 把這個(gè)接口類型也得放進(jìn)去(不然這個(gè)代理都不屬于這個(gè)類型,反射set的時(shí)候豈不直接報(bào)錯(cuò)了嗎????) if (dependencyType.isInterface()) { pf.addInterface(dependencyType); } return pf.getProxy(beanFactory.getBeanClassLoader()); } }
標(biāo)注有@Lazy
注解完成注入的時(shí)候,最終注入只是一個(gè)此處臨時(shí)生成的代理對(duì)象,只有在真正執(zhí)行目標(biāo)方法的時(shí)候才會(huì)去容器內(nèi)拿到真是的bean
實(shí)例來(lái)執(zhí)行目標(biāo)方法。
利用allowRawInjectionDespiteWrapping屬性來(lái)強(qiáng)制改變判斷
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowRawInjectionDespiteWrapping(true); } }
看完上述內(nèi)容,你們對(duì)Springboot中怎么實(shí)現(xiàn)Spring循環(huán)依賴有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。