中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

wifi擴(kuò)展器做網(wǎng)站百度資源平臺(tái)鏈接提交

wifi擴(kuò)展器做網(wǎng)站,百度資源平臺(tái)鏈接提交,商丘網(wǎng)站網(wǎng)站建設(shè),購物網(wǎng)站建設(shè)計(jì)劃書文章目錄 一、目標(biāo):通過三級(jí)緩存解決循環(huán)依賴二、設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴2.1 通過三級(jí)緩存解決循環(huán)依賴2.2 嘗試使用一級(jí)緩存解決循環(huán)依賴 三、實(shí)現(xiàn):通過三級(jí)緩存解決循環(huán)依賴3.1 工程結(jié)構(gòu)3.2 通過三級(jí)緩存解決循環(huán)依賴類圖3.3 設(shè)置三…

文章目錄

  • 一、目標(biāo):通過三級(jí)緩存解決循環(huán)依賴
  • 二、設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴
    • 2.1 通過三級(jí)緩存解決循環(huán)依賴
    • 2.2 嘗試使用一級(jí)緩存解決循環(huán)依賴
  • 三、實(shí)現(xiàn):通過三級(jí)緩存解決循環(huán)依賴
    • 3.1 工程結(jié)構(gòu)
    • 3.2 通過三級(jí)緩存解決循環(huán)依賴類圖
    • 3.3 設(shè)置三級(jí)緩存
      • 3.3.1 對(duì)象工廠
      • 3.3.2 設(shè)置三級(jí)緩存
    • 3.4 提前暴露對(duì)象
      • 3.4.1 實(shí)例化感知對(duì)象處理
      • 3.4.2 默認(rèn)自動(dòng)代理創(chuàng)建者
      • 3.4.3 實(shí)現(xiàn)默認(rèn)bean創(chuàng)建的抽象bean工廠超類
  • 四、測試:通過三級(jí)緩存解決循環(huán)依賴
    • 4.1 添加測試配置
      • 4.1.1 老公類
      • 4.1.2 媳婦類
      • 4.1.3 婆婆接口
      • 4.1.4 婆婆代理類
      • 4.1.5 切面
      • 4.1.6 Spring屬性配置文件
    • 4.2 單元測試
  • 五、總結(jié):通過三級(jí)緩存解決循環(huán)依賴

一、目標(biāo):通過三級(jí)緩存解決循環(huán)依賴

💡 如何解決類與類之間的循環(huán)依賴?

  • 在目前的 Spring 框架中,如果你配置了 A、B 兩個(gè) Bean 對(duì)象互相依賴,那么立刻會(huì)拋出 java.lang.StackOverflowError,為什么?
    • 因?yàn)?A 創(chuàng)建時(shí)需要依賴 B 創(chuàng)建,而 B 的創(chuàng)建又依賴于 A 創(chuàng)建,就這樣死循環(huán)了。
  • 循環(huán)依賴 基本可以說是 Spring 中經(jīng)典的實(shí)現(xiàn),所要解決的場景主要三種情況。

在這里插入圖片描述

  • 循環(huán)依賴主要分為三種:自身依賴于自身、互相循環(huán)依賴、多組循環(huán)依賴。
  • 但無論循環(huán)依賴的數(shù)量有多少,循環(huán)依賴的本質(zhì)是一樣。
    • 就是你的完整創(chuàng)建依賴于我,而我的完整創(chuàng)建也依賴于你,但我們互相沒法解耦,最終導(dǎo)致依賴創(chuàng)建失敗。
  • 所以需要 Spring 提供除了構(gòu)造函數(shù)注入和原型注入外的,setter 循環(huán)依賴注入解決方案。

二、設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴

2.1 通過三級(jí)緩存解決循環(huán)依賴

💡 設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴

  • 用于解決循環(huán)依賴需要用到三個(gè)緩存,這三個(gè)緩存分別存放:
    • 成品對(duì)象、半成品對(duì)象(未填充屬性值)、代理對(duì)象,分階段存放對(duì)象內(nèi)容,來解決循環(huán)依賴問題。
  • 需要知道核心原理:用于解決循環(huán)依賴就必須是三級(jí)緩存嗎?二級(jí)緩存行嗎?一級(jí)緩存行嗎?
    • 其實(shí)都能解決。但是 Spring 框架的實(shí)現(xiàn)要保證幾個(gè)事情。如:
      • 只有一級(jí)緩存處理流程沒法拆分,復(fù)雜度也會(huì)增加,同時(shí)半成品對(duì)象可能會(huì)有空指針異常。
      • 而將半成品與成品對(duì)象分開,處理起來也更加優(yōu)雅、簡單、易擴(kuò)展。
    • 另外 Spring 的兩大特性中不僅有 IOC,還有 AOP,也就是基于字節(jié)碼增強(qiáng)后的方法,該存放到哪。
      • 而三級(jí)緩存最主要,要解決的循環(huán)依賴就是對(duì) AOP 的處理,但如果把 AOP 代理對(duì)象的創(chuàng)建提前,那么二級(jí)緩存也一樣可以解決。
      • 但是,這就違背了 Spring 創(chuàng)建對(duì)象的原則,Spring 更喜歡把所有的普通 Bean 都初始化完成,再處理代理對(duì)象的初始化。
  • 思考:如果有對(duì)象不只是簡單的對(duì)象,還有代理對(duì)象,還有 AOP 應(yīng)用,要怎么處理這樣的依賴問題。

在這里插入圖片描述

  • 關(guān)于循環(huán)依賴在目前的 Spring 框架中,主要就是對(duì)于創(chuàng)建的提前暴露。
    • 如果是工廠對(duì)象則會(huì)使用 getEarlyBeanReference 邏輯提前將工廠對(duì)象存放到三級(jí)緩存中。
    • 等到后續(xù)獲取對(duì)象的時(shí)候?qū)嶋H拿到的是工廠對(duì)象中 getObject,這個(gè)才是最終的實(shí)際對(duì)象。
  • 在創(chuàng)建對(duì)象的 AbstractAutowireCapableBeanFactory#doCreateBean 方法中,提前暴露對(duì)象以后。
    • 就可以通過接下來的流程,getSingleton 從三個(gè)緩存中以此尋找對(duì)象。
    • 一級(jí)、二級(jí)如果有則直接取走,如果對(duì)象是三級(jí)緩存中則會(huì)從三級(jí)緩存中獲取后并刪掉工廠對(duì)象,把實(shí)際對(duì)象放到二級(jí)緩存中。
  • 最后是關(guān)于單例的對(duì)象的注冊(cè)操作,這個(gè)注冊(cè)操作就是把真實(shí)的實(shí)際對(duì)象放到一級(jí)緩存中,因?yàn)榇藭r(shí)它已經(jīng)是一個(gè)成品對(duì)象了。

2.2 嘗試使用一級(jí)緩存解決循環(huán)依賴

在這里插入圖片描述

  • 如果僅以一級(jí)緩存解決循環(huán)依賴,那么在實(shí)現(xiàn)上可以通過 A 對(duì)象 newInstance 創(chuàng)建且未填充屬性后,直接放入緩存中。
  • A 對(duì)象的屬性填充 B 對(duì)象時(shí),如果緩存中不能獲取到 B 對(duì)象,則開始創(chuàng)建 B 對(duì)象,同樣創(chuàng)建完成后,把 B 對(duì)象填充到緩存中。
  • 接下來就開始對(duì) B 對(duì)象的屬性進(jìn)行填充,恰好這會(huì)可以從緩存中拿到半成品的 A 對(duì)象,那么這個(gè)時(shí)候 B 對(duì)象的屬性就填充完了。
  • 最后返回來繼續(xù)完成 A 對(duì)象的屬性填充,把實(shí)例化后并填充了屬性的 B 對(duì)象賦值給 A 對(duì)象的 b 屬性,這樣就完成了一個(gè)循環(huán)依賴操作。

CircleTest.java

package com.lino.springframework.test;import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @description: 循環(huán)依賴案例*/
public class CircleTest {private final static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);public static void main(String[] args) throws Exception {System.out.println(getBean(B.class).getA());System.out.println(getBean(A.class).getB());}private static <T> T getBean(Class<T> beanClass) throws Exception {String beanName = beanClass.getSimpleName().toLowerCase();if (singletonObjects.containsKey(beanName)) {return (T) singletonObjects.get(beanName);}// 實(shí)例化對(duì)象入緩存Object obj = beanClass.newInstance();singletonObjects.put(beanName, obj);// 屬性填充補(bǔ)全對(duì)象Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {field.setAccessible(true);Class<?> fieldClass = field.getType();String fieldBeanName = fieldClass.getSimpleName().toLowerCase();field.set(obj, singletonObjects.containsKey(fieldBeanName) ? singletonObjects.get(fieldBeanName) : getBean(fieldClass));field.setAccessible(false);}return (T) obj;}
}class A {private B b;public B getB() {return b;}public void setB(B b) {this.b = b;}
}class B {private A a;public A getA() {return a;}public void setA(A a) {this.a = a;}
}

測試結(jié)果

com.lino.springframework.test.A@266474c2
com.lino.springframework.test.B@6f94fa3e

在這里插入圖片描述

  • 從測試效果和截圖依賴過程中可以看到,一級(jí)緩存也可以解決簡單場景的循環(huán)依賴問題。
  • 其實(shí) getBean,是整個(gè)解決循環(huán)依賴的核心內(nèi)容,A 創(chuàng)建后填充屬性時(shí)依賴 B,那么就去創(chuàng)建 B,在創(chuàng)建 B 開始填充時(shí)發(fā)現(xiàn)依賴于 A,但此時(shí) A 這個(gè)半成品對(duì)象已經(jīng)存放在緩存到 singletonObjects 中了,所以 B 可以正常創(chuàng)建,再通過遞歸把 A 也創(chuàng)建完整了。

三、實(shí)現(xiàn):通過三級(jí)緩存解決循環(huán)依賴

3.1 工程結(jié)構(gòu)

spring-step-16
|-src|-main|	|-java|		|-com.lino.springframework|			|-aop|			|	|-aspectj|			|	|	|-AspectJExpressionPointcut.java|			|	|	|-AspectJExpressionPointcutAdvisor.java|			|	|-framework|			|	|	|-adapter|			|	|	|	|-MethodBeforeAdviceInterceptor.java|			|	|	|-autoproxy|			|	|	|	|-DefaultAdvisorAutoProxyCreator.java|			|	|	|-AopProxy.java|			|	|	|-Cglib2AopProxy.java|			|	|	|-JdkDynamicAopProxy.java|			|	|	|-ProxyFactory.java|			|	|	|-ReflectiveMethodInvocation.java|			|	|-AdvisedSupport.java|			|	|-Advisor.java|			|	|-BeforeAdvice.java|			|	|-ClassFilter.java|			|	|-MethodBeforeAdvice.java|			|	|-MethodMatcher.java|			|	|-Pointcut.java|			|	|-PointcutAdvisor.java|			|	|-TargetSource.java|			|-beans|			|	|-factory|			|	|	|-annotation|			|	|	|	|-Autowired.java|			|	|	|	|-AutowiredAnnotationBeanPostProcessor.java|			|	|	|	|-Qualifier.java|			|	|	|	|-Value.java|			|	|	|-config|			|	|	|	|-AutowireCapableBeanFactory.java|			|	|	|	|-BeanDefinition.java|			|	|	|	|-BeanFactoryPostProcessor.java|			|	|	|	|-BeanPostProcessor.java|			|	|	|	|-BeanReference.java|			|	|	|	|-ConfigurableBeanFactory.java|			|	|	|	|-InstantiationAwareBeanPostProcessor.java|			|	|	|	|-SingletonBeanRegistry.java|			|	|	|-support|			|	|	|	|-AbstractAutowireCapableBeanFactory.java|			|	|	|	|-AbstractBeabDefinitionReader.java|			|	|	|	|-AbstractBeabFactory.java|			|	|	|	|-BeabDefinitionReader.java|			|	|	|	|-BeanDefinitionRegistry.java|			|	|	|	|-CglibSubclassingInstantiationStrategy.java|			|	|	|	|-DefaultListableBeanFactory.java|			|	|	|	|-DefaultSingletonBeanRegistry.java|			|	|	|	|-DisposableBeanAdapter.java|			|	|	|	|-FactoryBeanRegistrySupport.java|			|	|	|	|-InstantiationStrategy.java|			|	|	|	|-SimpleInstantiationStrategy.java|			|	|	|-xml|			|	|	|	|-XmlBeanDefinitionReader.java|			|	|	|-Aware.java|			|	|	|-BeanClassLoaderAware.java|			|	|	|-BeanFactory.java|			|	|	|-BeanFactoryAware.java|			|	|	|-BeanNameAware.java|			|	|	|-ConfigurableListableBeanFactory.java|			|	|	|-DisposableBean.java|			|	|	|-FactoryBean.java|			|	|	|-HierarcgicalBeanFactory.java|			|	|	|-InitializingBean.java|			|	|	|-ListableBeanFactory.java|			|	|	|-ObjectFactory.java|			|	|	|-PropertyPlaceholderConfigurer.java|			|	|-BeansException.java|			|	|-PropertyValue.java|			|	|-PropertyValues.java|			|-context|			|	|-annotation|			|	|	|-ClassPathBeanDefinitionScanner.java|			|	|	|-ClassPathScanningCandidateComponentProvider.java|			|	|	|-Scope.java|			|	|-event|			|	|	|-AbstractApplicationEventMulticaster.java|			|	|	|-ApplicationContextEvent.java|			|	|	|-ApplicationEventMulticaster.java|			|	|	|-ContextclosedEvent.java|			|	|	|-ContextRefreshedEvent.java|			|	|	|-SimpleApplicationEventMulticaster.java|			|	|-support|			|	|	|-AbstractApplicationContext.java|			|	|	|-AbstractRefreshableApplicationContext.java|			|	|	|-AbstractXmlApplicationContext.java|			|	|	|-ApplicationContextAwareProcessor.java|			|	|	|-ClassPathXmlApplicationContext.java|			|	|-ApplicationContext.java|			|	|-ApplicationContextAware.java|			|	|-ApplicationEvent.java|			|	|-ApplicationEventPublisher.java|			|	|-ApplicationListener.java|			|	|-ConfigurableApplicationContext.java|			|-core.io|			|	|-ClassPathResource.java|			|	|-DefaultResourceLoader.java|			|	|-FileSystemResource.java|			|	|-Resource.java|			|	|-ResourceLoader.java|			|	|-UrlResource.java|			|-stereotype|			|	|-Component.java|			|-util|			|	|-ClassUtils.java|			|	|-StringValueResolver.java|-test|-java|-com.lino.springframework.test|-bean|	|-Husband.java|	|-HusbandMother.java|	|-IMother.java|	|-SpouseAdvice.java|	|-Wife.java|-ApiTest.java|-CircleTest.java|-resources|-spring.xml

3.2 通過三級(jí)緩存解決循環(huán)依賴類圖

在這里插入圖片描述

  • 循環(huán)依賴的黑犀牛功能實(shí)現(xiàn)主要包括 DefaultSingletonBeanRegistry 提供三級(jí)緩存。
    • singletonObjects、earlySingletonObjects、singletonFactiries,分別存放成品對(duì)象、半成品對(duì)象和工廠對(duì)象。
    • 同時(shí)包裝三個(gè)緩存提供方法:getSingleton、registerSingleton、addSingletonFactory,這樣使用方就可以分別在不同時(shí)間段存放和獲取對(duì)應(yīng)的對(duì)象。
  • AbstractAutowireCapableBeanFactorydoCreateBean 方法中,提供了關(guān)于提前暴露對(duì)象的操作。
    • addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean))
    • 以及后續(xù)獲取對(duì)象和注冊(cè)對(duì)象的操作:exposedObject = getSingleton(beanName)registerSingleton(beanName, exposedObject)。
    • 經(jīng)過這樣的處理就可以完成對(duì)復(fù)雜場景循環(huán)依賴的操作。
  • 另外在 DefaultAdvisorAutoProxyCreator 提供的切面服務(wù)中,也需要實(shí)現(xiàn)接口 InstantiationAwareBeanPostProcessor 新增的 getEarlyBeanReference 方法,便于把依賴的切面對(duì)象也能存放到三級(jí)緩存中,處理對(duì)應(yīng)的循環(huán)依賴。

3.3 設(shè)置三級(jí)緩存

3.3.1 對(duì)象工廠

ObjectFactory.java

package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;/*** @description: 對(duì)象工廠*/
public interface ObjectFactory<T> {/*** 獲取對(duì)象** @return 泛型對(duì)象* @throws BeansException 異常*/T getObject() throws BeansException;
}

3.3.2 設(shè)置三級(jí)緩存

DefaultSingletonBeanRegistry.java

package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.DisposableBean;
import com.lino.springframework.beans.factory.ObjectFactory;
import com.lino.springframework.beans.factory.config.SingletonBeanRegistry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;/*** @description: 通用的注冊(cè)表實(shí)現(xiàn)*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {protected static final Object NULL_OBJECT = new Object();/*** 一級(jí)緩存,普通對(duì)象*/private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();/*** 二級(jí)緩存,提前暴露對(duì)象,沒有完全實(shí)例化的對(duì)象*/protected final Map<String, Object> earlySingletonObjects = new HashMap<>();/*** 三級(jí)緩存,存放代理對(duì)象*/private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();private final Map<String, DisposableBean> disposableBeans = new HashMap<>();@Overridepublic Object getSingleton(String beanName) {Object singletonObject = singletonObjects.get(beanName);if (null == singletonObject) {singletonObject = earlySingletonObjects.get(beanName);// 判斷二級(jí)緩存中是否有對(duì)象,這個(gè)對(duì)象就是代理對(duì)象,因?yàn)橹挥写韺?duì)象才會(huì)放到三級(jí)緩存中if (null == singletonObject) {ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 把三級(jí)緩存中的代理對(duì)象中的真實(shí)對(duì)象獲取出來,放入二級(jí)緩存中earlySingletonObjects.put(beanName, singletonObject);singletonFactories.remove(beanName);}}}return singletonObject;}@Overridepublic void registerSingletonBean(String beanName, Object singletonObject) {singletonObjects.put(beanName, singletonObject);earlySingletonObjects.remove(beanName);singletonFactories.remove(beanName);}protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}public void registerDisposableBean(String beanName, DisposableBean bean) {disposableBeans.put(beanName, bean);}public void destroySingletons() {Set<String> keySet = this.disposableBeans.keySet();Object[] disposableBeanNames = keySet.toArray();for (int i = disposableBeanNames.length - 1; i >= 0; i--) {Object beanName = disposableBeanNames[i];DisposableBean disposableBean = disposableBeans.remove(beanName);try {disposableBean.destroy();} catch (Exception e) {throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);}}}
}
  • 在用于提供單例對(duì)象注冊(cè)操作的 DefaultSingletonBeanRegistry 類中,共有三個(gè)緩存對(duì)象的屬性:
    • singletonObjectsearlySingletonObjects、singletonFactories
    • 用于存放不同類型的對(duì)象:單例對(duì)象、早期的半成品單例對(duì)象、單例工廠對(duì)象。
  • 緊接著在這三個(gè)緩存對(duì)象下提供了獲取、添加和注冊(cè)不同對(duì)象的方法,包括:getSingleton、registerSingletonBeanaddSingletonFactory。
    • 后面的兩個(gè)方法都比較簡單,主要是 getSingleton 的操作,它是一層層處理不同時(shí)期的單例對(duì)象,直至拿到有效的對(duì)象。

3.4 提前暴露對(duì)象

3.4.1 實(shí)例化感知對(duì)象處理

InstantiationAwareBeanPostProcessor.java

package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;/*** @description: 實(shí)例化感知對(duì)象處理*/
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {.../*** 在 Spring 中由 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference 提供** @param bean     對(duì)象* @param beanName 對(duì)象名稱* @return 二級(jí)緩存對(duì)象*/default Object getEarlyBeanReference(Object bean, String beanName) {return bean;}
}
  • 添加 getEarlyBeanReference 緩存二級(jí)緩存對(duì)象方法

3.4.2 默認(rèn)自動(dòng)代理創(chuàng)建者

DefaultAdvisorAutoProxyCreator.java

package com.lino.springframework.aop.framework.autoproxy;import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;/*** @description: 默認(rèn)自動(dòng)代理創(chuàng)建者*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {private DefaultListableBeanFactory beanFactory;private final Set<Object> earlyProxyReferences = Collections.synchronizedSet(new HashSet<>());@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (DefaultListableBeanFactory) beanFactory;}@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {return true;}private boolean isInfrastructureClass(Class<?> beanClass) {return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (!earlyProxyReferences.contains(beanName)) {return wrapIfNecessary(bean, beanName);}return bean;}protected Object wrapIfNecessary(Object bean, String beanName) {if (isInfrastructureClass(bean.getClass())) {return bean;}Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();for (AspectJExpressionPointcutAdvisor advisor : advisors) {ClassFilter classFilter = advisor.getPointcut().getClassFilter();// 過濾匹配類if (!classFilter.matches(bean.getClass())) {continue;}AdvisedSupport advisedSupport = new AdvisedSupport();TargetSource targetSource = new TargetSource(bean);advisedSupport.setTargetSource(targetSource);advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());advisedSupport.setProxyTargetClass(true);// 返回代理對(duì)象return new ProxyFactory(advisedSupport).getProxy();}return bean;}@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {earlyProxyReferences.add(beanName);return wrapIfNecessary(bean, beanName);}@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {return pvs;}
}

3.4.3 實(shí)現(xiàn)默認(rèn)bean創(chuàng)建的抽象bean工廠超類

AbstractAutowireCapableBeanFactory.java

package com.lino.springframework.beans.factory.support;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** @description: 實(shí)現(xiàn)默認(rèn)bean創(chuàng)建的抽象bean工廠超類*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {// 判斷是否返回代理 Bean 對(duì)象Object bean = resolveBeforeInstantiation(beanName, beanDefinition);if (null != bean) {return bean;}return doCreateBean(beanName, beanDefinition, args);}protected Object doCreateBean(String beanName, BeanDefinition beanDefinition, Object[] args) {Object bean = null;try {// 實(shí)例化Beanbean = createBeanInstance(beanDefinition, beanName, args);// 處理循環(huán)依賴,將實(shí)例化后的Bean對(duì)象提前放入緩存中暴露出來if (beanDefinition.isSingleton()) {Object finalBean = bean;addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));}// 實(shí)例化后判斷boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);if (!continueWithPropertyPopulation) {return bean;}// 在設(shè)置Bean屬性之前,允許 BeanPostProcessor修改屬性值applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);// 給bean填充屬性applyPropertyValues(beanName, bean, beanDefinition);// 執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}// 注冊(cè)實(shí)現(xiàn) DisposableBean 接口的 Bean 對(duì)象registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);// 判斷 SCOPE_SINGLETON、SCOPE_PROTOTYPEObject exposedObject = bean;if (beanDefinition.isSingleton()) {// 獲取代理對(duì)象exposedObject = getSingleton(beanName);registerSingletonBean(beanName, exposedObject);}return exposedObject;}protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {Object exposedObject = bean;for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {exposedObject = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).getEarlyBeanReference(exposedObject, beanName);if (null == exposedObject) {return exposedObject;}}}return exposedObject;}...
}
  • AbstractAutowireCapableBeanFactory#doCreateBean 的方法中主要是擴(kuò)展了對(duì)象的提前暴露 addSingletonFactory,和單例對(duì)象的獲取 getSingleton,以及注冊(cè)操作 registerSingletonBean
  • getEarlyBeanReference 方法就是定義在如 AOP 切面中這樣的代理對(duì)象。

四、測試:通過三級(jí)緩存解決循環(huán)依賴

4.1 添加測試配置

4.1.1 老公類

Husband.java

package com.lino.springframework.test.bean;/*** @description: 老公類*/
public class Husband {private Wife wife;public String queryWife() {return "Husband.wife";}public Wife getWife() {return wife;}public void setWife(Wife wife) {this.wife = wife;}
}

4.1.2 媳婦類

Wife.java

package com.lino.springframework.test.bean;/*** @description: 媳婦類*/
public class Wife {private Husband husband;private IMother mother;public String queryHusband() {return "Wife.husband、Mother.callMother: " + mother.callMother();}public Husband getHusband() {return husband;}public void setHusband(Husband husband) {this.husband = husband;}public IMother getMother() {return mother;}public void setMother(IMother mother) {this.mother = mother;}
}

4.1.3 婆婆接口

IMother.java

package com.lino.springframework.test.bean;/*** @description: 婆婆接口*/
public interface IMother {String callMother();
}

4.1.4 婆婆代理類

HusbandMother.java

package com.lino.springframework.test.bean;import com.lino.springframework.beans.factory.FactoryBean;
import java.lang.reflect.Proxy;/*** @description: 老公婆婆類*/
public class HusbandMother implements FactoryBean<IMother> {@Overridepublic IMother getObject() throws Exception {return (IMother) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IMother.class},(proxy, method, args) -> "婚后媳婦媽媽的職責(zé)被婆婆代理了!" + method.getName());}@Overridepublic Class<?> getObjectType() {return IMother.class;}@Overridepublic boolean isSingleton() {return true;}
}

4.1.5 切面

SpouseAdvice.java

package com.lino.springframework.test.bean;import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;/*** @description: 攔截器*/
public class SpouseAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("關(guān)懷小兩口(切面):" + method);}
}

4.1.6 Spring屬性配置文件

spring.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="husband" class="com.lino.springframework.test.bean.Husband"><property name="wife" ref="wife"/></bean><bean id="husbandMother" class="com.lino.springframework.test.bean.HusbandMother"/><bean id="wife" class="com.lino.springframework.test.bean.Wife"><property name="husband" ref="husband"/><property name="mother" ref="husbandMother"/></bean><!--AOP 配置,驗(yàn)證三級(jí)緩存    --><bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/><bean id="beforeAdvice" class="com.lino.springframework.test.bean.SpouseAdvice"/><bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor"><property name="advice" ref="beforeAdvice"/></bean><bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor"><property name="expression" value="execution(* com.lino.springframework.test.bean.Wife.*(..))"/><property name="advice" ref="methodInterceptor"/></bean></beans>

4.2 單元測試

ApiTest.java

@Test
public void test_autoProxy() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");Husband husband = applicationContext.getBean("husband", Husband.class);Wife wife = applicationContext.getBean("wife", Wife.class);System.out.println("老公的媳婦:" + husband.queryWife());System.out.println("媳婦的老公:" + wife.queryHusband());
}

測試結(jié)果

老公的媳婦:Husband.wife
關(guān)懷小兩口(切面)public java.lang.String com.lino.springframework.test.bean.Wife.queryHusband()
媳婦的老公:Wife.husband、Mother.callMother: 婚后媳婦媽媽的職責(zé)被婆婆代理了!callMother

在這里插入圖片描述

  • 測試結(jié)果看,無論是簡單對(duì)象依賴,還是代理工程對(duì)象,或者 AOP 切面對(duì)象,都可以在三級(jí)緩存下解決循環(huán)依賴的問題。
  • 此外從運(yùn)行截圖 DefaultSingletonBeanRegistry#getSingleton 中也可以看到需要三級(jí)緩存存放工廠對(duì)象的類,都會(huì)使用到 getObject 獲取真實(shí)對(duì)象,并隨后存入半成品對(duì)象 earlySingletonObjects 中以及移除工廠對(duì)象。

五、總結(jié):通過三級(jí)緩存解決循環(huán)依賴

  • Spring 中所有的功能都是以解決 Java 編程中的特性而存在的,就像我們處理的循環(huán)依賴,如果沒有 Spring 框架的情況下,可能我們也會(huì)盡可能避免寫出循環(huán)依賴的操作,因?yàn)樵跊]有經(jīng)過加工處理后,這樣的依賴關(guān)系肯定會(huì)報(bào)錯(cuò)的。
    • 這也是程序從 能用好用 的升級(jí)。
  • 在解決循環(huán)依賴的核心流程中,主要是提前暴露對(duì)象的設(shè)計(jì),以及建立三級(jí)緩存的數(shù)據(jù)結(jié)構(gòu)來存放不同時(shí)期的對(duì)象。
    • 如果說沒有如切面和工廠中的代理對(duì)象,那么二級(jí)緩存也就可以解決了,哪怕是只有一級(jí)緩存。
    • 但為了設(shè)計(jì)上的合理和可擴(kuò)展性,所以創(chuàng)建了三級(jí)緩存來放置不同時(shí)期的對(duì)象。
http://www.risenshineclean.com/news/61539.html

相關(guān)文章:

  • 鄭州好的網(wǎng)站設(shè)計(jì)公司搜索引擎關(guān)鍵詞排名優(yōu)化
  • 項(xiàng)城做網(wǎng)站搜索引擎的網(wǎng)址有哪些
  • 政府門戶網(wǎng)站什么意思搜索引擎優(yōu)化seo優(yōu)惠
  • wordpress添加關(guān)鍵詞描述seo優(yōu)化在線診斷
  • 蘇州營銷網(wǎng)站建設(shè)公司杭州seo搜索引擎優(yōu)化
  • vps網(wǎng)站設(shè)置搜索引擎優(yōu)化的基礎(chǔ)是什么
  • 四川專門做招聘酒的網(wǎng)站網(wǎng)頁制作公司排名
  • 網(wǎng)站建設(shè)公司 南京舉例一個(gè)成功的網(wǎng)絡(luò)營銷案例
  • 網(wǎng)站開發(fā)平臺(tái)的定義鴻星爾克網(wǎng)絡(luò)營銷案例分析
  • 重慶市建設(shè)網(wǎng)站站長網(wǎng)站seo查詢
  • 怎么查網(wǎng)站有沒有做404營銷推廣工作內(nèi)容
  • 網(wǎng)上商城建設(shè)seo策略是什么意思
  • 杭州設(shè)計(jì)公司網(wǎng)站排名黃岡免費(fèi)網(wǎng)站推廣平臺(tái)匯總
  • 用asp.net做的網(wǎng)站實(shí)例行業(yè)關(guān)鍵詞搜索排名
  • 商城類的網(wǎng)站怎么做北京競價(jià)托管代運(yùn)營
  • 杭州做網(wǎng)站hzyze域名在線查詢
  • 廣州免費(fèi)接種宮頸癌疫苗推廣關(guān)鍵詞優(yōu)化
  • 個(gè)人做網(wǎng)站猛賺錢seo優(yōu)化有百度系和什么
  • vue.js做的網(wǎng)站資源貓
  • 找手工活帶回家做的找工作哪個(gè)網(wǎng)站最靠譜內(nèi)容營銷
  • 專門做淘寶特價(jià)的網(wǎng)站網(wǎng)站模板免費(fèi)下載
  • 網(wǎng)站開發(fā)需求表模板個(gè)人網(wǎng)站制作模板主頁
  • 比較著名的seo網(wǎng)站點(diǎn)擊器免費(fèi)版
  • 做網(wǎng)站和網(wǎng)頁區(qū)別省委副書記
  • ps怎么做網(wǎng)站首頁和超鏈接注冊(cè)一個(gè)公司網(wǎng)站需要多少錢
  • 汕頭網(wǎng)站建設(shè)備案關(guān)鍵詞優(yōu)化seo外包
  • 做外貿(mào)要看哪些網(wǎng)站app運(yùn)營推廣策劃方案
  • 濮陽做網(wǎng)站建設(shè)的公司最好的推廣平臺(tái)排名
  • 上海品牌網(wǎng)站建設(shè)公司廣州市口碑seo推廣
  • 自己做的網(wǎng)站怎么設(shè)置文件下載seo優(yōu)化顧問服務(wù)