精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

日韩精品福利网站| 亚洲成人你懂的| 92国产精品视频| 国产网友自拍视频| 国产精品一区2区3区| 在线亚洲一区二区| 国内外成人激情免费视频| 日韩一级免费毛片| 日本不卡一二三区黄网| 色综合久久中文字幕综合网小说| 亚洲av成人无码一二三在线观看| 在线观看精品| 亚洲精品伦理在线| 日本欧美精品久久久| 亚洲精品国产手机| 久久精品国产精品亚洲红杏| 97在线免费视频| 国产高清视频免费在线观看| 国产99久久| 亚洲精品一区二区三区福利| 亚洲国产高清av| 老色鬼在线视频| 中文字幕一区二区三区不卡在线| 国产高清在线精品一区二区三区| 中文天堂在线资源| 国产欧美一级| 久久久久久久影院| 黑鬼狂亚洲人videos| 精品国产日韩欧美| 精品一区二区三区电影| 好吊操视频这里只有精品| 国产精品99久久久久久董美香| 亚洲国产日韩在线一区模特| 四虎影院一区二区| 午夜看片在线免费| 久久众筹精品私拍模特| 国产视频一区二区不卡| 精品国产区一区二| 精品一区二区三区视频在线观看| 国产成人精品日本亚洲专区61| 久久精品国产亚洲av香蕉| 艳女tv在线观看国产一区| 一本久久综合亚洲鲁鲁| 最近中文字幕免费| 精品一区欧美| 亚洲美女av网站| 一级做a爰片毛片| 久久av国产紧身裤| 亚洲精品福利在线观看| www.男人天堂| 欧美理伦片在线播放| 精品日韩欧美一区二区| 无码人妻丰满熟妇区毛片蜜桃精品| 伊人久久一区| 欧美精品丝袜久久久中文字幕| 亚洲精品午夜在线观看| 日本久久久久| 宅男噜噜噜66一区二区66| 天天影视色综合| 成人自拍视频| 日韩欧美在线一区二区三区| 特种兵之深入敌后| av不卡一区| 亚洲国产天堂久久综合网| 9.1成人看片| 国产亚洲一区| 日韩一区在线视频| 国产va在线播放| 亚洲麻豆视频| 日韩av黄色在线观看| 亚洲高清在线看| 美女网站一区二区| 99re热精品| 天天躁日日躁狠狠躁喷水| 久久久精品天堂| 中文字幕久久综合| 国内在线免费视频| 色悠悠亚洲一区二区| 亚洲这里只有精品| 91在线一区| 国产视频精品va久久久久久| 日韩一级片在线免费观看| 91精品一区二区三区综合| 欧美第一页在线| 婷婷激情五月网| 久久精品国内一区二区三区| 成人午夜影院在线观看| 日本福利在线观看| 亚洲视频在线观看三级| 婷婷五月综合缴情在线视频| 成人免费看视频网站| 欧美高清你懂得| 人妻无码中文久久久久专区| 日韩精品免费| 91av福利视频| 国产精品亚洲欧美在线播放| 97精品视频在线观看自产线路二| 亚洲国产精品www| 在线视频国产区| 91搞黄在线观看| 精品国产乱码久久久久夜深人妻| 中文字幕精品影院| 色综合五月天导航| 国产精品无码粉嫩小泬| 成人av免费网站| 宅男一区二区三区| 亚洲天堂导航| 精品日韩99亚洲| 国产精品精品软件男同| 性8sex亚洲区入口| 国产91免费视频| 久久久久久久久免费视频| 黑人狂躁日本妞一区二区三区| 九九九九九国产| 欧美禁忌电影网| 久久免费国产精品1| 91超薄丝袜肉丝一区二区| 91美女片黄在线观看91美女| 日韩一区二区高清视频| 久久爱.com| 亚洲香蕉在线观看| 欧美日韩精品区| 成人午夜激情片| www.-级毛片线天内射视视| 日本另类视频| 亚洲人成在线观看| 中国一级免费毛片| 不卡在线视频中文字幕| 日本中文字幕一级片| 四虎精品在线观看| 中文字幕欧美专区| 国产精品第六页| 久久久777精品电影网影网 | 日本道色综合久久影院| 亚洲精品无amm毛片| 亚洲免费在线看| 亚洲精品mv在线观看| 欧美xxxx中国| 91精品国产综合久久久久久久久| a中文在线播放| 在线观看欧美日本| 亚洲午夜精品久久久久久高潮 | 7777免费精品视频| 欧性猛交ⅹxxx乱大交| 亚洲综合免费观看高清完整版 | 青青久久aⅴ北条麻妃| 无码h黄肉3d动漫在线观看| 亚洲国产一区二区三区青草影视| 超碰人人cao| 欧美精品入口| 国产精品入口免费| 77thz桃花论族在线观看| 亚洲成年人在线| 国产成人亚洲欧洲在线| 91在线精品一区二区三区| 欧美 日本 亚洲| 伊人久久大香线蕉无限次| 国产精品成人va在线观看| 成人精品一区| 欧美一区二区美女| 久草免费新视频| jlzzjlzz亚洲日本少妇| 黄色影院一级片| 国产a久久精品一区二区三区| 秋霞午夜一区二区| 在线免费观看黄色网址| 91精品国产品国语在线不卡| 国产一级久久久| 91美女福利视频| 鲁一鲁一鲁一鲁一av| 亚洲国产不卡| 国产精品视频入口| 向日葵视频成人app网址| 日韩中文字幕免费视频| 丰满人妻一区二区三区无码av| 午夜精品久久久久久久久| 成人免费毛片糖心| 国产真实乱偷精品视频免| 精品视频在线观看一区二区| 亚洲人成网亚洲欧洲无码| 国产精品丝袜久久久久久高清 | 欧美电影一二区| 91黄在线观看| 另类专区亚洲| 美女扒开尿口让男人操亚洲视频网站| 亚洲精品一区二区三区蜜桃| 日韩欧美视频一区二区三区| 国产极品美女在线| 北条麻妃国产九九精品视频| 最新中文字幕免费视频| 亚洲视频免费| 亚洲日本欧美在线| 日韩美脚连裤袜丝袜在线| 国产一区二区丝袜| 亚洲天堂手机| 欧美老女人在线视频| 福利小视频在线观看| 精品久久久三级丝袜| 一区二区视频网站| 精品久久久久久久大神国产| 国产精品国产三级国产传播| 久久综合999| 亚洲图片欧美另类| 久久电影国产免费久久电影| 俄罗斯av网站| 精久久久久久| 中国一级黄色录像| 精品国产一级毛片| 乱色588欧美| 国产精品视屏| 99在线免费观看视频| 国产第一亚洲| 国产成人+综合亚洲+天堂| segui88久久综合| 久久夜色精品亚洲噜噜国产mv| 男女污视频在线观看| 精品日韩在线观看| 精品国产18久久久久久| 精品视频资源站| 日韩手机在线视频| 红桃视频成人在线观看| 永久免费看黄网站| 亚洲免费在线看| 无码人妻精品中文字幕| 欧美国产97人人爽人人喊| 一区二区三区四区免费| 99视频精品全部免费在线| 亚洲精品无码一区二区| 高清国产一区二区| 久久久久无码精品| 国产成人综合网| 国内av免费观看| 国产精品综合视频| 肉色超薄丝袜脚交| 国内精品写真在线观看| 天天看片天天操| 久久精品国产成人一区二区三区| 手机看片福利日韩| 午夜在线视频观看日韩17c| 日韩av一二三四区| 中文在线一区| 亚洲中文字幕无码中文字| 国产精品久久久一区二区| 777精品久无码人妻蜜桃| 亚洲影视在线| 在线视频日韩一区| 麻豆国产精品777777在线| 日本中文字幕影院| 国产一区二区不卡| 初高中福利视频网站| av网站一区二区三区| 国产精品麻豆入口| 91麻豆精品秘密| 成人无码av片在线观看| 欧美精彩视频一区二区三区| 午夜黄色福利视频| 亚洲色图欧洲色图| 国产精品白浆一区二小说| 精品国产乱码久久久久久天美| 亚洲熟女综合色一区二区三区| 色偷偷久久一区二区三区| 中文在线最新版天堂| 91精品一区二区三区在线观看| 国产av一区二区三区精品| 亚洲成人av在线播放| 亚洲aaa在线观看| 在线观看91久久久久久| 大片免费在线观看| 久久久免费av| 欧美亚洲大片| 91丝袜脚交足在线播放| 亚洲精华一区二区三区| 亚洲人成影视在线观看| 国内精品久久久久久久97牛牛| 毛片在线播放视频| 毛片不卡一区二区| 中文字幕人妻熟女人妻a片| www激情久久| 潘金莲一级黄色片| 精品国产精品三级精品av网址| 中文字幕 国产精品| 日韩免费一区二区| 国产资源在线观看| 欧美大片在线看| 国精产品一区一区三区四川| 亚洲综合自拍一区| 神马久久一区二区三区| 国产免费内射又粗又爽密桃视频| 在线综合欧美| 欧美污在线观看| 久久精品一区二区| 国产在线视频你懂的| 欧美视频在线一区二区三区| 日韩中文字幕影院| www亚洲精品| 欧美www.| 国产精品麻豆免费版| 久久视频国产| 日韩a在线播放| 国产精品一级片| 在线免费观看视频| 五月天一区二区三区| 国产露脸91国语对白| 亚洲人成电影网站色| aaa在线播放视频| 91精品久久久久久久久中文字幕 | 成人亚洲视频| 久久精品成人一区二区三区蜜臀| 中文字幕日韩欧美精品高清在线| 激情视频综合网| 99国产精品国产精品久久| 免费在线观看一级片| 欧美日韩一区二区三区不卡| 人操人视频在线观看| 久久久久久国产精品美女| 国产电影一区| 亚洲欧美日韩另类精品一区二区三区| 亚洲一区亚洲| av无码一区二区三区| 亚洲一二三专区| 精品黑人一区二区三区国语馆| 中文字幕亚洲一区二区三区五十路| 性爽视频在线| 久久成人资源| 99国产精品久久久久久久成人热| 国产一级二级av| 亚洲毛片av在线| 国产精品久久影视| 久久精品国产精品亚洲| 国语自产精品视频在线看抢先版结局| 欧美精品一区三区在线观看| 国产一级久久| 黄瓜视频污在线观看| 欧美视频在线免费看| 四虎国产精品永远| 91精品国产乱码久久久久久蜜臀 | 日韩精品福利视频| 久久精品天堂| 欧美熟妇激情一区二区三区| 一本色道综合亚洲| 国产一级网站视频在线| 国产成人精品亚洲精品| 欧美一级精品| 日韩成人精品视频在线观看| 国产精品久久二区二区| 国产精品久久影视| 欧美激情va永久在线播放| 欧美日韩中出| 美女扒开大腿让男人桶| 99久久婷婷国产精品综合| 久久久精品免费看| 亚洲色图50p| 久久精品97| 成年人三级视频| 成人视屏免费看| 99视频在线看| 国产亚洲精品91在线| 少妇高潮一区二区三区99| 国产又粗又爽又黄的视频| 国产成人午夜高潮毛片| 成年人免费看毛片| 亚洲一区二区久久久| 亚洲综合视频| 可以在线看的av网站| 久久精品一二三| 国产日韩精品suv| 97色在线观看| 欧美日韩国产高清电影| 午夜免费视频网站| 午夜精品在线视频一区| yiren22亚洲综合伊人22| 91天堂在线视频| 国产精品亚洲欧美| 国产wwwwxxxx| 精品久久久久久最新网址| 欧美7777| 玖玖精品在线视频| 久久先锋影音av鲁色资源| 中文字幕av无码一区二区三区| 欧美另类在线观看| 国产日韩欧美一区二区三区| 国产精欧美一区二区三区白种人| 亚洲国产cao| av福利精品| 国产日韩二区| 久草精品在线观看| 久久久久久久极品| 麻豆乱码国产一区二区三区| 免费毛片在线不卡| 一区二区在线免费观看视频| 色久综合一二码| 日本色护士高潮视频在线观看| 日本精品一区| 不卡电影一区二区三区| 亚洲一区中文字幕在线| 88xx成人精品| 欧美日韩国产色综合一二三四| 国产真人做爰视频免费| 亚洲国产精品小视频| 国产精品一区免费在线|