精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一文搞懂 Spring 循環依賴

開發 前端
一般來說,如果我們的代碼中出現了循環依賴,則說明我們的代碼在設計的過程中可能存在問題,我們應該盡量避免循環依賴的發生。不過一旦發生了循環依賴,Spring 默認也幫我們處理好了,當然這并不能說明循環依賴這種代碼就沒問題。

一 循環依賴

1.1 什么是循環依賴

首先,什么是循環依賴?這個其實好理解,就是兩個 Bean 互相依賴,類似下面這樣:

@Service
public class AService {
    @Autowired
    BService bService;
}
@Service
public class BService {
    @Autowired
    AService aService;
}

AService 和 BService 互相依賴:

圖片圖片

這個應該很好理解。

1.2 循環依賴的類型

一般來說,循環依賴有三種不同的形態,上面 1.1 小節是其中一種。

另外兩種分別是三者依賴,如下圖:

圖片圖片

這種循環依賴一般隱藏比較深,不易發覺。

還有自我依賴,如下圖:

圖片圖片

一般來說,如果我們的代碼中出現了循環依賴,則說明我們的代碼在設計的過程中可能存在問題,我們應該盡量避免循環依賴的發生。不過一旦發生了循環依賴,Spring 默認也幫我們處理好了,當然這并不能說明循環依賴這種代碼就沒問題。實際上在目前最新版的 Spring 中,循環依賴是要額外開啟的,如果不額外配置,發生了循環依賴就直接報錯了。

另外,Spring 并不能處理所有的循環依賴,后面松哥會和大家進行分析。

二 循環依賴解決思路

2.1 解決思路

那么對于循環依賴該如何解決呢?其實很簡單,中加加入一個緩存就可以了,小伙伴們來看下面這張圖:

圖片圖片

我們在這里引入了一個緩存池。

當我們需要創建 AService 的實例的時候,會首先通過 Java 反射創建出來一個原始的 AService,這個原始 AService 可以簡單理解為剛剛 new 出來(實際是剛剛通過反射創建出來)還沒設置任何屬性的 AService,此時,我們把這個 AService 先存入到一個緩存池中。

接下來我們就需要給 AService 的屬性設置值了,同時還要處理 AService 的依賴,這時我們發現 AService 依賴 BService,那么就去創建 BService 對象,結果創建 BService 的時候,發現 BService 依賴 AService,那么此時就先從緩存池中取出來 AService 先用著,然后繼續 BService 創建的后續流程,直到 BService 創建完成后,將之賦值給 AService,此時 AService 和 BService 就都創建完成了。

可能有小伙伴會說,BService 從緩存池中拿到的 AService 是一個半成品,并不是真正的最終的 AService,但是小伙伴們要知道,咱們 Java 是引用傳遞(也可以認為是值傳遞,只不過這個值是內存地址),BService 當時拿到的是 AService 的引用,說白了就是一塊內存地址而已,根據這個地址找到的就是 AService,所以,后續如果 AService 創建完成后,BService 所拿到的 AService 就是完整的 AService 了。

那么上面提到的這個緩存池,在 Spring 容器中有一個專門的名字,就叫做 earlySingletonObjects,這是 Spring 三級緩存中的二級緩存,這里保存的是剛剛通過反射創建出來的 Bean,這些 Bean 還沒有經歷過完整生命周期,Bean 的屬性可能都還沒有設置,Bean 需要的依賴都還沒有注入進來。另外兩級緩存分別是:

  • singletonObjects:這是一級緩存,一級緩存中保存的是所有經歷了完整生命周期的 Bean,即一個 Bean 從創建、到屬性賦值、到各種處理器的執行等等,都經歷過了,就存到 singletonObjects 中,當我們需要獲取一個 Bean 的時候,首先會去一級緩存中查找,當一級緩存中沒有的時候,才會考慮去二級緩存。
  • singletonFactories:這是三級緩存。在一級緩存和二級緩存中,緩存的 key 是 beanName,緩存的 value 則是一個 Bean 對象,但是在三級緩存中,緩存的 value 是一個 Lambda 表達式,通過這個 Lambda 表達式可以創建出來目標對象的一個代理對象。

有的小伙伴可能會覺得奇怪,按照上文的介紹,一級緩存和二級緩存就足以解決循環依賴了,為什么還冒出來一個三級緩存?那就得考慮 AOP 的情況了!

2.2 存在 AOP 怎么辦

上面松哥給大家介紹的是普通的 Bean 創建,那確實沒有問題。但是 Spring 中還有一個非常重要的能力,那就是 AOP。

說到這里,我得先和小伙伴么說一說 Spring 中 AOP 的創建流程。

正常來說是我們首先通過反射獲取到一個 Bean 的實例,然后就是給這個 Bean 填充屬性,屬性填充完畢之后,接下來就是執行各種 BeanPostProcessor 了,如果這個 Bean 中有需要代理的方法,那么系統就會自動配置對應的后置處理器,松哥舉一個簡單例子,假設我有如下一個 Service:

@Service
public class UserService {

    @Async
    public void hello() {
        System.out.println("hello>>>"+Thread.currentThread().getName());
    }
}

那么系統就會自動提供一個名為 AsyncAnnotationBeanPostProcessor 的處理器,在這個處理器中,系統會生成一個代理的 UserService 對象,并用這個對象代替原本的 UserService。

那么小伙伴們要搞清楚的是,原本的 UserService 和新生成的代理的 UserService 是兩個不同的對象,占兩塊不同的內存地址?。?!

我們再來回顧下面這張圖:

圖片圖片

如果 AService 最終是要生成一個代理對象的話,那么 AService 存到緩存池的其實還是原本的 AService,因為此時還沒到處理 AOP 那一步(要先給各個屬性賦值,然后才是 AOP 處理),這就導致 BService 從緩存池里拿到的 AService 是原本的 AService,等到 BService 創建完畢之后,AService 的屬性賦值才完成,接下來在 AService 后續的創建流程中,AService 會變成了一個代理對象了,不是緩存池里的 AService 了,最終就導致 BService 所依賴的 AService 和最終創建出來的 AService 不是同一個。

為了解決這個問題,Spring 引入了三級緩存 singletonFactories。

singletonFactories 的工作機制是這樣的(假設 AService 最終是一個代理對象):

當我們創建一個 AService 的時候,通過反射剛把原始的 AService 創建出來之后,先去判斷當前一級緩存中是否存在當前 Bean,如果不存在,則:

  1. 首先向三級緩存中添加一條記錄,記錄的 key 就是當前 Bean 的 beanName,value 則是一個 Lambda 表達式 ObjectFactory,通過執行這個 Lambda 可以給當前 AService 生成代理對象。
  2. 然后如果二級緩存中存在當前 AService Bean,則移除掉。

現在繼續去給 AService 各個屬性賦值,結果發現 AService 需要 BService,然后就去創建 BService,創建 BService 的時候,發現 BService 又需要用到 AService,于是就先去一級緩存中查找是否有 AService,如果有,就使用,如果沒有,則去二級緩存中查找是否有 AService,如果有,就使用,如果沒有,則去三級緩存中找出來那個 ObjectFactory,然后執行這里的 getObject 方法,這個方法在執行的過程中,會去判斷是否需要生成一個代理對象,如果需要就生成代理對象返回,如果不需要生成代理對象,則將原始對象返回即可。最后,把拿到手的對象存入到二級緩存中以備下次使用,同時刪除掉三級緩存中對應的數據。這樣 AService 所依賴的 BService 就創建好了。

接下來繼續去完善 AService,去執行各種后置的處理器,此時,有的后置處理器想給 AService 生成代理對象,發現 AService 已經是代理對象了,就不用生成了,直接用已有的代理對象去代替 AService 即可。

至此,AService 和 BService 都搞定。

本質上,singletonFactories 是把 AOP 的過程提前了。

2.3 小結

總的來說,Spring 解決循環依賴把握住兩個關鍵點:

  • 提前暴露:剛剛創建好的對象還沒有進行任何賦值的時候,將之暴露出來放到緩存中,供其他 Bean 提前引用(二級緩存)。
  • 提前 AOP:A 依賴 B 的時候,去檢查是否發生了循環依賴(檢查的方式就是將正在創建的 A 標記出來,然后 B 需要 A,B 去創建 A 的時候,發現 A 正在創建,就說明發生了循環依賴),如果發生了循環依賴,就提前進行 AOP 處理,處理完成后再使用(三級緩存)。

原本 AOP 這個過程是屬性賦完值之后,再由各種后置處理器去處理 AOP 的(AbstractAutoProxyCreator),但是如果發生了循環依賴,就先 AOP,然后屬性賦值,最后等到后置處理器執行的時候,就不再做 AOP 的處理了。

不過需要注意,三級緩存并不能解決所有的循環依賴。

嚴格來說,其實也不是解決不了,所有問題都有辦法解決,只是還需要額外配置。

三 特殊情況

根據前面介紹的思路,以下一些循環依賴場景無法解決。

3.1 基于構造器注入

如果依賴的對象是基于構造器注入的,那么執行的時候就會報錯,代碼如下:

@Service
public class AService {
    BService bService;

    public AService(BService bService) {
        this.bService = bService;
    }
}
@Service
public class BService {
    AService aService;

    public BService(AService aService) {
        this.aService = aService;
    }
}

運行時報錯如下:

圖片圖片

原因分析:

前面我們說解決循環依賴的思路是加入緩存,如下圖:

圖片圖片

我們說先把 AService 原始對象創建出來,存入到緩存池中,然后再處理 AService 中需要注入的外部 Bean 等等,但是,如果 AService 依賴的 BService 是通過構造器注入的,那就會導致在創建 AService 原始對象的時候就需要用到 BService,去創建 BService 時候又需要 AService,這樣就陷入到死循環了,對于這樣的循環依賴執行時候就會出錯。

更進一步,如果我們在 AService 中是通過 @Autowired 來注入 BService 的,那么應該是可以運行的,代碼如下:

@Service
public class AService {
    @Autowired
    BService bService;
}
@Service
public class BService {
    AService aService;

    public BService(AService aService) {
        this.aService = aService;
    }
}

上面這段代碼,AService 的原始對象就可以順利創建出來放到緩存池中,BService 創建所需的 AService 也就能從緩存中獲取到,所以就可以執行了。

3.2 prototype 對象

循環依賴雙方 scope 都是 prototype 的話,也會循環依賴失敗,代碼如下:

@Service
@Scope("prototype")
public class AService {
    @Autowired
    BService bService;
}
@Service
@Scope("prototype")
public class BService {
    @Autowired
    AService aService;
}

這種循環依賴運行時也會報錯,報錯信息如下(跟前面報錯信息一樣):

圖片圖片

原因分析:

scope 為 prototype 意思就是說這個 Bean 每次需要的時候都現場創建,不用緩存里的。那么 AService 需要 BService,所以就去現場創建 BService,結果 BService 又需要 AService,繼續現場創建,AService 又需要 BService...,所以最終就陷入到死循環了。

3.3 @Async

帶有 @Async 注解的 Bean 產生循環依賴,代碼如下:

@Service
public class AService {
    @Autowired
    BService bService;

    @Async
    public void hello() {

    }
}
@Service
public class BService {
    @Autowired
    AService aService;

}

報錯信息如下:

圖片圖片

其實大家從這段報錯信息中也能看出來個七七八八:在 BService 中注入了 AService 的原始對象,但是 AService 在后續的處理流程中被 AOP 代理了,產生了新的對象,導致 BService 中的 AService 并不是最終的 AService,所以就出錯了!

那有小伙伴要問了,前面我們不是說了三級緩存就是為了解決 AOP 問題嗎,為什么這里發生了 AOP 卻無法解決?

如下兩個前置知識大家先理解一下:

第一:

其實大部分的 AOP 循環依賴是沒有問題的,這個 @Async 只是一個特例,特別在哪里呢?一般的 AOP 都是由 AbstractAutoProxyCreator 這個后置處理器來處理的,通過這個后置處理器生成代理對象,AbstractAutoProxyCreator 后置處理器是 SmartInstantiationAwareBeanPostProcessor 接口的子類,并且 AbstractAutoProxyCreator 后置處理器重寫了 SmartInstantiationAwareBeanPostProcessor 接口的 getEarlyBeanReference 方法;而 @Async 是由 AsyncAnnotationBeanPostProcessor 來生成代理對象的,AsyncAnnotationBeanPostProcessor 也是 SmartInstantiationAwareBeanPostProcessor 的子類,但是卻沒有重寫 getEarlyBeanReference 方法,默認情況下,getEarlyBeanReference 方法就是將傳進來的 Bean 原封不動的返回去。

第二:

在 Bean 初始化的時候,Bean 創建完成后,后面會執行兩個方法:

  • populateBean:這個方法是用來做屬性填充的。
  • initializeBean:這個方法是用來初始化 Bean 的實例,執行工廠回調、init 方法以及各種 BeanPostProcessor。

大家先把這兩點搞清楚,然后我來跟大家說上面代碼的執行流程。

  1. 首先 AService 初始化,初始化完成之后,存入到三級緩存中。
  2. 執行 populateBean 方法進行 AService 的屬性填充,填充時發現需要用到 BService,于是就去初始化 BService。
  3. 初始化 BService 發現需要用到 AService,于是就去緩存池中找,找到之后拿來用,但是!!!這里找到的 AService 不是代理對象,而是原始對象。因為在三級緩存中保存的 AService 的那個 ObjectFactory 工廠,在對 AService 進行提前 AOP 的時候,執行的是 SmartInstantiationAwareBeanPostProcessor 類型的后置處理器 中的 getEarlyBeanReference 方法,如果是普通的 AOP,調用 getEarlyBeanReference 方法最終會觸發提前 AOP,但是,這里執行的是 AsyncAnnotationBeanPostProcessor 中的 getEarlyBeanReference 方法,該方法只是返回了原始的 Bean,并未做任何額外處理。
  4. 當 BService 創建完成后,AService 繼續初始化,繼續執行 initializeBean 方法。
  5. 在 initializeBean 方法中,執行其他的各種后置處理器,包括 AsyncAnnotationBeanPostProcessor,此時調用的是 AsyncAnnotationBeanPostProcessor 的 postProcessAfterInitialization 方法,在該方法中為 AService 生成了代理對象。
  6. 在 initializeBean 方法執行完成之后,AService 會繼續去檢查最終的 Bean 是不是還是一開始的 Bean,如果不是,就去檢查當前 Bean 有沒有被其他 Bean 引用過,如果被引用過,就會拋出來異常,也就是上圖大家看到的異常信息。

這就是松哥和大家分享的三種 Spring 默認無法解決的循環依賴,其實也不是無法解決,需要一些額外配置也能解決。

那么對于以上問題該如何解決?

Spring 里邊提供了辦法來解決,但是似乎又沒有解決,繼續看你就明白了。

四 @Lazy

前面提到的三種無法自動解決的循環依賴,都可以通過添加 @Lazy 注解來解決。

如果是構造器注入,如下:

@Service
public class AService {

    BService bService;

    @Lazy
    public AService(BService bService) {
        this.bService = bService;
    }

    public BService getbService() {
        return bService;
    }
}
@Service
public class BService {
    AService aService;
    
    @Lazy
    public BService(AService aService) {
        this.aService = aService;
    }

    public AService getaService() {
        return aService;
    }
}

@Lazy 注解可以添加在 AService 或者 BService 的構造方法上,也可以都添加上。

添加上之后,我們再去啟動項目,就不會報錯了。這樣看起來問題解決了,但是其實還是差點意思,小伙伴們看一下我的啟動代碼:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
AService aService = ctx.getBean(AService.class);
BService bService = ctx.getBean(BService.class);
System.out.println("aService.getClass() = " + aService.getClass());
System.out.println("bService.getClass() = " + bService.getClass());
System.out.println("aService.getbService().getClass() = " + aService.getbService().getClass());
System.out.println("bService.getaService().getClass() = " + bService.getaService().getClass());

最終打印結果如下:

圖片圖片

小伙伴們看到,我們從容器中獲取到的 AService 和 BService 的 Bean 都是正常的未被代理的對象,事實上我們的原始代碼確實也沒有需要代理的地方。但是,AService 中的 BService 以及 BService 中的 AService 卻都是代理對象,按理說 AService 中的 BService 應該和我們從 Spring 容器中獲取到的 BService 一致,BService 中的 AService 也應該和 Spring 容器中獲取到的 AService 一致,但實際上,兩者卻并不相同。

不過這樣也好懂了,為什么 Spring 能把一個死結給解開,就是因為 AService 和 BService 各自注入的 Bean 都不是原始的 Bean,都是一個代理的 Bean,AService 中注入的 BService 是一個代理對象,同理,BService 中注入的 AService 也是一個代理對象。

這也是為什么我一開始說這個問題 Spring 解決了又沒解決。

其實,這就是 @Lazy 這個注解的工作原理,看名字,加了該注解的對象會被延遲加載,實際上被該注解標記的對象,會自動生成一個代理對象。

前面提到的另外兩個問題,也可以通過 @Lazy 注解來解決,代碼如下:

@Service
@Scope("prototype")
public class AService {
    @Lazy
    @Autowired
    BService bService;

}
@Service
@Scope("prototype")
public class BService {
    @Lazy
    @Autowired
    AService aService;
}

這里 @Lazy 只要一個其實就能解決問題,也可以兩個都添加。

對于含有 @Async 注解的情況,也可以通過 @Lazy 注解來解決:

@Service
public class AService {
    @Autowired
    @Lazy
    BService bService;

    @Async
    public void hello() {
        bService.hello();
    }

    public BService getbService() {
        return bService;
    }
}
@Service
public class BService {
    @Autowired
    AService aService;

    public void hello() {
        System.out.println("xxx");
    }

    public AService getaService() {
        return aService;
    }
}

如此,循環依賴可破!

總而言之一句話,@Lazy 注解是通過建立一個中間代理層,來破解循環依賴的。

2. 原理分析

接下來我們再來簡單分析一下 @Lazy 注解處理的源碼。

先來回顧一下屬性注入的過程:

  1. 在創建 Bean 的時候,原始 Bean 創建出來之后,會調用 populateBean 方法進行 Bean 的屬性填充。
  2. 接下來調用 postProcessAfterInstantiation 方法去判斷是否需要執行后置處理器,如果不需要,就直接返回了。
  3. 調用 postProcessProperties 方法,去觸發各種后置處理器的執行。
  4. 在第 3 步的方法中,調用 findAutowiringMetadata,這個方法又會進一步觸發 buildAutorwiringMetadata 方法,去找到包含了 @Autowired、@Value 以及 @Inject 注解的屬性或者方法,并將之封裝為 InjectedElement 返回。
  5. 調用 InjectedElement#inject 方法進行屬性注入。
  6. 接下來執行 resolvedCachedArgument 方法嘗試從緩存中找到需要的 Bean 對象。
  7. 如果緩存中不存在,則調用 resolveFieldValue 方法去容器中找到 Bean。
  8. 最后調用 makeAccessible 和 set 方法完成屬性的賦值。

在第 7 步中,調用 resolveFieldValue 方法去解析 Bean,@Lazy 注解的相關邏輯就是在這個方法中進行處理的(對應 最新版 Spring 源碼視頻教程)。

resolveFieldValue 方法最終會執行到 resolveDependency 方法:

@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
 descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
 if (Optional.class == descriptor.getDependencyType()) {
  return createOptionalDependency(descriptor, requestingBeanName);
 }
 else if (ObjectFactory.class == descriptor.getDependencyType() ||
   ObjectProvider.class == descriptor.getDependencyType()) {
  return new DependencyObjectProvider(descriptor, requestingBeanName);
 }
 else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
  return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
 }
 else {
  Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
    descriptor, requestingBeanName);
  if (result == null) {
   result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
  }
  return result;
 }
}

在這個方法中,首先會判斷注入的屬性類型是 Optional、ObjectFactory 還是 JSR-330 中的注解,我們這里都不是,所以走最后一個分支。

在最后一個 else 中,首先調用 getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary 方法看一下是否需要延遲加載 Bean 對象,@Lazy 注解就是在這里進行處理的。如果能夠延遲加載,那么該方法的返回值就不為 null,就可以直接返回了,就不需要執行 doResolveDependency 方法了。

ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary:

@Override
@Nullable
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
 return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}

大家看一下,這個方法首先會調用 isLazy 去判斷一下是否需要延遲加載,如果需要,則調用 buildLazyResolutionProxy 方法構建一個延遲加載的對象;如果不需要,則直接返回一個 null 即可。

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;
}

這個判斷方法主要是檢查當前類中各種參數上是否含有 @Lazy 注解、方法、屬性以及類名上是否含有 @Lazy 注解,如果有,則返回 true,否則返回 false。

再來看 buildLazyResolutionProxy 方法:

private Object buildLazyResolutionProxy(
  final DependencyDescriptor descriptor, final @Nullable String beanName, boolean classOnly) {
 BeanFactory beanFactory = getBeanFactory();
 final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
 TargetSource ts = new TargetSource() {
  @Override
  public Class<?> getTargetClass() {
   return descriptor.getDependencyType();
  }
  @Override
  public boolean isStatic() {
   return false;
  }
  @Override
  public Object getTarget() {
   Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
   Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
   if (target == null) {
    Class<?> type = getTargetClass();
    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");
   }
   if (autowiredBeanNames != null) {
    for (String autowiredBeanName : autowiredBeanNames) {
     if (dlbf.containsBean(autowiredBeanName)) {
      dlbf.registerDependentBean(autowiredBeanName, beanName);
     }
    }
   }
   return target;
  }
  @Override
  public void releaseTarget(Object target) {
  }
 };
 ProxyFactory pf = new ProxyFactory();
 pf.setTargetSource(ts);
 Class<?> dependencyType = descriptor.getDependencyType();
 if (dependencyType.isInterface()) {
  pf.addInterface(dependencyType);
 }
 ClassLoader classLoader = dlbf.getBeanClassLoader();
 return (classOnly ? pf.getProxyClass(classLoader) : pf.getProxy(classLoader));
}

這個方法就是用來生成代理的對象的,這里構建了代理對象 TargetSource,在其 getTarget 方法中,會去執行 doResolveDependency 獲取到被代理的對象(doResolveDependency 的獲取邏輯可以參考 最新版 Spring 源碼視頻教程),而 getTarget 方法只有在需要的時候才會被調用。所以,@Lazy 注解所做的事情,就是在給 Bean 中的各個屬性注入值的時候,原本需要去 Spring 容器中找注入的對象,現在不找了,先給一個代理對象頂著,需要的時候再去 Spring 容器中查找

責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2024-04-12 12:19:08

語言模型AI

2022-03-24 08:51:48

Redis互聯網NoSQL

2025-03-17 00:21:00

2021-01-22 06:35:44

IoCxml驅動技術

2021-03-22 10:05:59

netstat命令Linux

2023-09-15 12:00:01

API應用程序接口

2023-09-08 08:20:46

ThreadLoca多線程工具

2017-11-29 13:55:55

神經網絡循環神經網絡RNN

2023-08-24 16:50:45

2023-04-03 15:04:00

RPCPHP語言

2019-11-19 08:00:00

神經網絡AI人工智能

2022-06-07 10:13:22

前端沙箱對象

2021-06-30 08:45:02

內存管理面試

2022-08-15 15:39:23

JavaScript面向對象數據

2021-01-13 05:21:59

參數

2023-10-16 08:16:31

Bean接口類型

2020-03-18 14:00:47

MySQL分區數據庫

2023-03-06 21:29:41

mmap技術操作系統

2023-05-22 13:27:17

2023-09-02 21:27:09

點贊
收藏

51CTO技術棧公眾號

国产在线观看第一页| 捆绑裸体绳奴bdsm亚洲| 中文字幕在线播放网址| 岛国精品在线观看| 青青草原一区二区| 激情五月激情综合| 欧美91在线| 精品视频资源站| www.欧美黄色| 色中色在线视频| 精品亚洲porn| 欧美性视频在线| 91杏吧porn蝌蚪| 亚洲婷婷伊人| 日韩欧美国产系列| 白嫩少妇丰满一区二区| 日韩精品卡一| 国产精品高潮呻吟久久| 国内成+人亚洲| 中文字幕人妻精品一区| 亚洲精品专区| 不卡中文字幕av| 中文字幕第24页| 台湾亚洲精品一区二区tv| 欧美一区二区三区喷汁尤物| 日本精品免费在线观看| 男插女视频久久久| 国产精品成人免费| 日产国产精品精品a∨| 好吊视频一区二区三区| 精品在线免费观看| 国产精品精品一区二区三区午夜版| 久久丫精品久久丫| 88国产精品视频一区二区三区| 亚洲人成网在线播放| yjizz视频| 另类视频一区二区三区| 欧美妇女性影城| 亚洲 欧美 另类人妖| 女生影院久久| 欧美性xxxx极品hd满灌| 全黄性性激高免费视频| 男男gaygays亚洲| 一区二区三区四区五区视频在线观看| 亚洲一二三区在线| 岛国在线大片| 国产日韩欧美麻豆| 色一情一区二区三区四区| 日本人妖在线| 91亚洲资源网| 免费中文日韩| 暖暖视频在线免费观看| 久久久久高清精品| 日韩激情视频| a视频网址在线观看| 国产日韩av一区| 涩涩涩999| 色影视在线观看| 亚洲欧美色综合| 黄色小视频大全| av网站大全在线| 一区二区三区在线免费播放| 97中文字幕在线| 国产盗摄——sm在线视频| 亚洲国产一区二区三区| 农民人伦一区二区三区| 精精国产xxxx视频在线播放| 狠狠躁夜夜躁久久躁别揉| 国产精品专区在线| 亚洲风情在线资源| 在线精品视频免费播放| 亚洲一级免费在线观看| 欧美特黄不卡| 亚洲国产精品久久91精品| 亚洲 欧美 日韩在线| 国产精品115| 亚洲精品一二区| av网站免费在线看| 99国产精品一区二区| 久久99精品久久久久久噜噜| 日韩无码精品一区二区三区| 麻豆精品网站| 91亚洲va在线va天堂va国 | 成人性生交大片免费看小说| 国产精品自产拍| 成人国产精品免费观看动漫| 欧美日韩一区综合| 自拍视频在线免费观看| 一区二区三区波多野结衣在线观看| 91免费黄视频| 日韩制服一区| 日韩美女一区二区三区| 在线 丝袜 欧美 日韩 制服| 欧美电影免费播放| 欧美精品第一页在线播放| 国产无套丰满白嫩对白| 久久精品国产999大香线蕉| 成人情视频高清免费观看电影| 你懂的免费在线观看视频网站| 综合av第一页| 无码精品国产一区二区三区免费| 日韩成人精品一区二区三区| 亚洲精品一区二区三区影院 | 亚洲美女精品一区| 久久无码高潮喷水| 人人爱人人干婷婷丁香亚洲| 亚洲欧美在线x视频| 久久久久亚洲av无码专区体验| 六月婷婷一区| 9a蜜桃久久久久久免费| 第九色区av在线| 午夜国产精品一区| 午夜影院免费版| 清纯唯美综合亚洲| 国产91精品久久久| 风流少妇一区二区三区91| 国产精品三级av| 欧美成人xxxxx| 一区中文字幕电影| 精品国产依人香蕉在线精品| 国产又黄又粗又爽| 国产suv一区二区三区88区| 午夜精品亚洲一区二区三区嫩草 | 欧美性猛交xxxx免费看久久久| 亚洲制服中文字幕| 日韩中文欧美| 国产脚交av在线一区二区| 天堂在线视频网站| 亚洲国产精品人人做人人爽| 一区二区三区四区毛片| 欧美一二区在线观看| 992tv成人免费视频| 亚洲xxxx天美| 一区二区三区四区视频精品免费 | 成人精品小视频| 老牛精品亚洲成av人片| 欧美激情久久久| 99在线观看免费| 国产精品久久久久久户外露出| 亚洲熟妇av一区二区三区| 精品福利一区| 97超级碰碰碰| 日韩在线无毛| 天天综合日日夜夜精品| 国产精品麻豆入口| 亚洲精品一二| 久久99影院| 天堂√中文最新版在线| 日韩精品在线免费| 亚洲久久在线观看| 2023国产精品| 国产成人a亚洲精v品无码| 欧美黑人巨大videos精品| 午夜精品www| 亚洲人在线观看视频| 福利二区91精品bt7086| 免费在线观看你懂的| 模特精品在线| 五月天亚洲综合情| 欧美天堂在线| 久久久91精品国产| 亚洲黄色片视频| 同产精品九九九| 一区二区三区免费在线观看视频| 西西人体一区二区| 午夜精品福利一区二区| 精品国产一区二| 欧美激情一区二区三区成人| 亚洲色图21p| 欧洲一区二区三区在线| 糖心vlog免费在线观看 | 岛国视频一区免费观看| 精品一性一色一乱农村| 亚洲精品国产精品自产a区红杏吧 亚洲精品国产精品乱码不99按摩 亚洲精品国产精品久久清纯直播 亚洲精品国产精品国自产在线 | 久久综合av免费| 色一情一乱一伦一区二区三区日本| 欧美先锋资源| 99久久一区三区四区免费| sm久久捆绑调教精品一区| 亚洲网站在线看| 国产亲伦免费视频播放| 精品久久久久久亚洲精品| jizz18女人高潮| 国产成人99久久亚洲综合精品| 日韩在线综合网| 天天天综合网| 久久久久久亚洲精品不卡4k岛国| 色综合天天色| 国内精品久久久久久久| aaa在线免费观看| 欧美成人性战久久| 五月激情丁香网| 亚洲永久精品大片| 久操视频在线观看免费| 成人中文字幕合集| 亚洲一区在线不卡| 亚洲精品美女| 99热一区二区三区| 亚洲日产av中文字幕| 亚洲综合日韩在线| 日韩在线影院| 久久久人成影片一区二区三区观看| 国产有码在线| 亚洲成人久久一区| 国产精品久久久久久久免费 | 日本一区二区三区免费乱视频| 在线成人精品视频| 日本中文一区二区三区| xxxx18hd亚洲hd捆绑| 图片区亚洲欧美小说区| 欧美精品在线一区| 6080成人| 亚洲tv在线观看| 精品成人免费一区二区在线播放| 欧美黑人视频一区| 麻豆tv入口在线看| 尤物九九久久国产精品的特点| 姝姝窝人体www聚色窝| 欧美一区二区在线看| 亚洲精品国产精品国自产网站按摩| 亚洲影院理伦片| 夫妻性生活毛片| 国产女人aaa级久久久级| 精品黑人一区二区三区观看时间| 国产黑丝在线一区二区三区| 色噜噜狠狠永久免费| 日韩av在线发布| 北条麻妃在线一区| 亚洲女同在线| 日本中文字幕片| 国产深夜精品| www.射射射| 伊人精品成人久久综合软件| 欧美精品一区二区性色a+v| 欧州一区二区| 天天综合狠狠精品| 日本成人小视频| 亚洲国产精品久久久久婷婷老年| 久久av影视| 欧美亚洲一级二级| 亚洲人成精品久久久 | 亚洲国产精品久久艾草纯爱| 麻豆亚洲av熟女国产一区二| 一区二区高清免费观看影视大全| 特级片在线观看| 亚洲综合色视频| 久久久久久久福利| 亚洲国产欧美在线| 精品91久久久| 欧美性猛交xxxx免费看漫画| 国产又大又粗又爽| 91黄色免费版| 中文字幕第315页| 欧美猛男gaygay网站| av手机免费看| 亚洲成人aaa| 亚洲色偷精品一区二区三区| 亚洲女成人图区| h视频在线播放| 久久国产精品电影| 欧美家庭影院| 欧美一级片在线播放| 五月激情久久| 91香蕉电影院| 美女一区二区在线观看| 欧美在线播放一区| 日韩欧美高清在线播放| 女女百合国产免费网站| 亚洲激情二区| 久久精品午夜福利| 紧缚捆绑精品一区二区| 少妇搡bbbb搡bbb搡打电话| 91网站在线观看视频| 91激情视频在线观看| 亚洲精品视频自拍| av黄色在线看| 欧美日韩国产片| 免费观看黄色av| 国产亚洲欧美aaaa| 中文字幕在线观看网站| 性色av一区二区三区红粉影视| 成人软件在线观看| 99久久99久久精品国产片| 日本午夜精品| 一区二区三区欧美成人| 雨宫琴音一区二区在线| 97公开免费视频| 国产精品1024久久| 老牛影视av老牛影视av| 亚洲欧美综合网| 成人毛片在线播放| 欧美一级夜夜爽| 黄色片在线播放| 久久久久久久久久久av| 福利一区视频| 久久久水蜜桃| 欧美淫片网站| 亚洲无吗一区二区三区| 成人美女在线视频| 91免费在线看片| 精品久久久中文| 亚洲成熟女性毛茸茸| 在线电影欧美日韩一区二区私密| 午夜伦理在线视频| 国产精品日韩精品| 香蕉久久夜色精品国产使用方法| 亚洲AV无码成人精品一区| 男人天堂欧美日韩| 佐佐木明希电影| 最新久久zyz资源站| 亚洲综合图片网| 亚洲国产精品电影| 一二三四区在线观看| 国产精品美女免费视频| 亚洲理论电影| 少妇高潮喷水在线观看| 国产福利一区二区三区在线视频| 国产熟女一区二区| 日韩欧美亚洲综合| 无码精品人妻一区二区| 欧美另类xxx| **日韩最新| 亚洲巨乳在线观看| 日本欧美一区二区在线观看| 欧美做受喷浆在线观看| 亚洲高清在线精品| 成人免费公开视频| 欧美成人自拍视频| 99精品国产九九国产精品| 亚洲va久久久噜噜噜久久狠狠 | 亚洲日本在线视频观看| 中文字幕在线观看精品| 亚洲一区二区黄| 超碰一区二区| 欧美激情一区二区三区在线视频 | 欧美大片aaa| 日本欧美中文字幕| 在线观看欧美理论a影院| 国产美女无遮挡网站| 99re这里只有精品首页| 日韩女同强女同hd| 亚洲国产日韩欧美在线99| xxx.xxx欧美| 精品日产一区2区三区黄免费| 尤物在线精品| 一女三黑人理论片在线| 色综合亚洲欧洲| 国产理论电影在线观看| 国产精品国产亚洲伊人久久| 欧美手机视频| 亚洲成人福利在线| 亚洲精品亚洲人成人网在线播放| 国产欧美日韩综合精品一区二区三区| 美女黄色丝袜一区| 亚洲免费一区三区| 成人免费视频91| 91麻豆国产福利精品| 亚洲 欧美 中文字幕| 一区二区三区视频观看| 国产精品免费无遮挡| 亚洲片在线观看| aaaa欧美| 国产高清精品软男同| 国产激情偷乱视频一区二区三区| 久青草视频在线观看| 日韩大片免费观看视频播放 | 91九色在线视频| 欧美日韩精品| 国产ts丝袜人妖系列视频| 色噜噜久久综合| 在线免费av网站| 91亚色免费| 国产亚洲欧洲| av免费播放网站| 日韩女优视频免费观看| 僵尸再翻生在线观看免费国语| 日韩精品久久一区二区三区| 精品一区二区成人精品| 久久精品人妻一区二区三区| 日韩电视剧免费观看网站| 免费在线观看一区| 免费的av在线| 久久综合九色欧美综合狠狠| 亚洲天堂avav| 国内精品久久久久久影视8| 成人vr资源| 成人一区二区三区仙踪林| 日韩欧美国产激情| 欧美一区二区三区| 精品无人乱码一区二区三区的优势| 青青国产91久久久久久| 久久婷婷国产麻豆91| 中文欧美日本在线资源| 精品国产乱子伦一区二区| 亚洲天堂网一区| 午夜a成v人精品| а√资源新版在线天堂| 奇米888一区二区三区| 国产成人免费视频精品含羞草妖精| 在线观看日本视频|