日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【死磕 Spring】—– IOC 之 Factory 实例化 bean

發(fā)布時(shí)間:2025/3/20 javascript 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【死磕 Spring】—– IOC 之 Factory 实例化 bean 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
這篇我們關(guān)注創(chuàng)建 bean 過程中的第一個(gè)步驟:實(shí)例化 bean,對(duì)應(yīng)的方法為: createBeanInstance(),如下:
  • protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

  • // 解析 bean,將 bean 類名解析為 class 引用

  • Class<?> beanClass = resolveBeanClass(mbd, beanName);


  • if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {

  • throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  • "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());

  • }


  • // 如果存在 Supplier 回調(diào),則使用給定的回調(diào)方法初始化策略

  • Supplier<?> instanceSupplier = mbd.getInstanceSupplier();

  • if (instanceSupplier != null) {

  • return obtainFromSupplier(instanceSupplier, beanName);

  • }


  • // 如果工廠方法不為空,則使用工廠方法初始化策略

  • if (mbd.getFactoryMethodName() != null) {

  • return instantiateUsingFactoryMethod(beanName, mbd, args);

  • }


  • boolean resolved = false;

  • boolean autowireNecessary = false;

  • if (args == null) {

  • // constructorArgumentLock 構(gòu)造函數(shù)的常用鎖

  • synchronized (mbd.constructorArgumentLock) {

  • // 如果已緩存的解析的構(gòu)造函數(shù)或者工廠方法不為空,則可以利用構(gòu)造函數(shù)解析

  • // 因?yàn)樾枰鶕?jù)參數(shù)確認(rèn)到底使用哪個(gè)構(gòu)造函數(shù),該過程比較消耗性能,所有采用緩存機(jī)制

  • if (mbd.resolvedConstructorOrFactoryMethod != null) {

  • resolved = true;

  • autowireNecessary = mbd.constructorArgumentsResolved;

  • }

  • }

  • }

  • // 已經(jīng)解析好了,直接注入即可

  • if (resolved) {

  • // 自動(dòng)注入,調(diào)用構(gòu)造函數(shù)自動(dòng)注入

  • if (autowireNecessary) {

  • return autowireConstructor(beanName, mbd, null, null);

  • }

  • else {

  • // 使用默認(rèn)構(gòu)造函數(shù)構(gòu)造

  • return instantiateBean(beanName, mbd);

  • }

  • }


  • // 確定解析的構(gòu)造函數(shù)

  • // 主要是檢查已經(jīng)注冊(cè)的 SmartInstantiationAwareBeanPostProcessor

  • Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

  • if (ctors != null ||

  • mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||

  • mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

  • // 構(gòu)造函數(shù)自動(dòng)注入

  • return autowireConstructor(beanName, mbd, ctors, args);

  • }


  • //使用默認(rèn)構(gòu)造函數(shù)注入

  • return instantiateBean(beanName, mbd);

  • }

  • 實(shí)例化 bean 是一個(gè)復(fù)雜的過程,其主要的邏輯為:

    如果存在 Supplier 回調(diào),則調(diào)用 obtainFromSupplier() 進(jìn)行初始化

    如果存在工廠方法,則使用工廠方法進(jìn)行初始化

    首先判斷緩存,如果緩存中存在,即已經(jīng)解析過了,則直接使用已經(jīng)解析了的,根據(jù) constructorArgumentsResolved 參數(shù)來判斷是使用構(gòu)造函數(shù)自動(dòng)注入還是默認(rèn)構(gòu)造函數(shù)

    如果緩存中沒有,則需要先確定到底使用哪個(gè)構(gòu)造函數(shù)來完成解析工作,因?yàn)橐粋€(gè)類有多個(gè)構(gòu)造函數(shù),每個(gè)構(gòu)造函數(shù)都有不同的構(gòu)造參數(shù),所以需要根據(jù)參數(shù)來鎖定構(gòu)造函數(shù)并完成初始化,如果存在參數(shù)則使用相應(yīng)的帶有參數(shù)的構(gòu)造函數(shù),否則使用默認(rèn)構(gòu)造函數(shù)。

    下面就上面四種情況做分別說明。

    obtainFromSupplier()

  • Supplier<?> instanceSupplier = mbd.getInstanceSupplier();

  • if (instanceSupplier != null) {

  • return obtainFromSupplier(instanceSupplier, beanName);

  • }

  • 首先從 BeanDefinition 中獲取 Supplier,如果不為空,則調(diào)用 obtainFromSupplier() 。那么 Supplier 是什么呢?在這之前也沒有提到過這個(gè)字段。

  • public interface Supplier<T> {

  • T get();

  • }

  • Supplier 接口僅有一個(gè)功能性的 get(),該方法會(huì)返回一個(gè) T 類型的對(duì)象,有點(diǎn)兒類似工廠方法。這個(gè)接口有什么作用?用于指定創(chuàng)建 bean 的回調(diào),如果我們?cè)O(shè)置了這樣的回調(diào),那么其他的構(gòu)造器或者工廠方法都會(huì)沒有用。在什么設(shè)置該參數(shù)呢?Spring 提供了相應(yīng)的 setter 方法,如下:

  • public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {

  • this.instanceSupplier = instanceSupplier;

  • }

  • 在構(gòu)造 BeanDefinition 的時(shí)候設(shè)置了該值,如下(以 RootBeanDefinition 為例):

  • public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {

  • super();

  • setBeanClass(beanClass);

  • setScope(scope);

  • setInstanceSupplier(instanceSupplier);

  • }

  • 如果設(shè)置了 instanceSupplier 則調(diào)用 obtainFromSupplier() 完成 bean 的初始化,如下:

  • protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {

  • String outerBean = this.currentlyCreatedBean.get();

  • this.currentlyCreatedBean.set(beanName);

  • Object instance;

  • try {

  • // 調(diào)用 Supplier 的 get(),返回一個(gè)對(duì)象

  • instance = instanceSupplier.get();

  • }

  • finally {

  • if (outerBean != null) {

  • this.currentlyCreatedBean.set(outerBean);

  • }

  • else {

  • this.currentlyCreatedBean.remove();

  • }

  • }

  • // 根據(jù)對(duì)象構(gòu)造 BeanWrapper 對(duì)象

  • BeanWrapper bw = new BeanWrapperImpl(instance);

  • // 初始化 BeanWrapper

  • initBeanWrapper(bw);

  • return bw;

  • }

  • 代碼很簡(jiǎn)單,調(diào)用 調(diào)用 Supplier 的 get() 方法,獲得一個(gè) bean 實(shí)例對(duì)象,然后根據(jù)該實(shí)例對(duì)象構(gòu)造一個(gè) BeanWrapper 對(duì)象 bw,最后初始化該對(duì)象。有關(guān)于 BeanWrapper 后面專門出文講解。

    instantiateUsingFactoryMethod()

    如果存在工廠方法,則調(diào)用 instantiateUsingFactoryMethod() 完成 bean 的初始化工作(方法實(shí)現(xiàn)比較長,細(xì)節(jié)比較復(fù)雜,各位就硬著頭皮看吧)。

  • protected BeanWrapper instantiateUsingFactoryMethod(

  • String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

  • return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);

  • }

  • 構(gòu)造一個(gè) ConstructorResolver 對(duì)象,然后調(diào)用其 instantiateUsingFactoryMethod() 方法。ConstructorResolver 是構(gòu)造方法或者工廠類初始化 bean 的委托類。

  • public BeanWrapper instantiateUsingFactoryMethod(

  • final String beanName, final RootBeanDefinition mbd, @Nullable final Object[] explicitArgs) {


  • // 構(gòu)造 BeanWrapperImpl 對(duì)象

  • BeanWrapperImpl bw = new BeanWrapperImpl();

  • // 初始化 BeanWrapperImpl

  • // 向BeanWrapper對(duì)象中添加 ConversionService 對(duì)象和屬性編輯器 PropertyEditor 對(duì)象

  • //

  • this.beanFactory.initBeanWrapper(bw);


  • Object factoryBean;

  • Class<?> factoryClass;

  • boolean isStatic;


  • // 工廠名不為空

  • String factoryBeanName = mbd.getFactoryBeanName();

  • if (factoryBeanName != null) {

  • if (factoryBeanName.equals(beanName)) {

  • throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,

  • "factory-bean reference points back to the same bean definition");

  • }

  • // 獲取工廠實(shí)例

  • factoryBean = this.beanFactory.getBean(factoryBeanName);

  • if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {

  • throw new ImplicitlyAppearedSingletonException();

  • }

  • factoryClass = factoryBean.getClass();

  • isStatic = false;

  • }

  • else {

  • // 工廠名為空,則其可能是一個(gè)靜態(tài)工廠


  • // 靜態(tài)工廠創(chuàng)建bean,必須要提供工廠的全類名

  • if (!mbd.hasBeanClass()) {

  • throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,

  • "bean definition declares neither a bean class nor a factory-bean reference");

  • }

  • factoryBean = null;

  • factoryClass = mbd.getBeanClass();

  • isStatic = true;

  • }


  • // 工廠方法

  • Method factoryMethodToUse = null;

  • ConstructorResolver.ArgumentsHolder argsHolderToUse = null;

  • // 參數(shù)

  • Object[] argsToUse = null;


  • // 工廠方法的參數(shù)

  • // 如果指定了構(gòu)造參數(shù)則直接使用

  • // 在調(diào)用 getBean 方法的時(shí)候指定了方法參數(shù)

  • if (explicitArgs != null) {

  • argsToUse = explicitArgs;

  • }

  • else {

  • // 沒有指定,則嘗試從配置文件中解析

  • Object[] argsToResolve = null;

  • // 首先嘗試從緩存中獲取

  • synchronized (mbd.constructorArgumentLock) {

  • // 獲取緩存中的構(gòu)造函數(shù)或者工廠方法

  • factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;

  • if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {

  • // 獲取緩存中的構(gòu)造參數(shù)

  • argsToUse = mbd.resolvedConstructorArguments;

  • if (argsToUse == null) {

  • // 獲取緩存中的構(gòu)造函數(shù)參數(shù)的包可見字段

  • argsToResolve = mbd.preparedConstructorArguments;

  • }

  • }

  • }

  • // 緩存中存在,則解析存儲(chǔ)在 BeanDefinition 中的參數(shù)

  • // 如給定方法的構(gòu)造函數(shù) A(int ,int ),則通過此方法后就會(huì)把配置文件中的("1","1")轉(zhuǎn)換為 (1,1)

  • // 緩存中的值可能是原始值也有可能是最終值

  • if (argsToResolve != null) {

  • argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);

  • }

  • }


  • //

  • if (factoryMethodToUse == null || argsToUse == null) {

  • // 獲取工廠方法的類全名稱

  • factoryClass = ClassUtils.getUserClass(factoryClass);


  • // 獲取所有待定方法

  • Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);

  • // 檢索所有方法,這里是對(duì)方法進(jìn)行過濾

  • List<Method> candidateSet = new ArrayList<>();

  • for (Method candidate : rawCandidates) {

  • // 如果有static 且為工廠方法,則添加到 candidateSet 中

  • if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {

  • candidateSet.add(candidate);

  • }

  • }


  • Method[] candidates = candidateSet.toArray(new Method[0]);

  • // 排序構(gòu)造函數(shù)

  • // public 構(gòu)造函數(shù)優(yōu)先參數(shù)數(shù)量降序,非public 構(gòu)造函數(shù)參數(shù)數(shù)量降序

  • AutowireUtils.sortFactoryMethods(candidates);


  • // 用于承載解析后的構(gòu)造函數(shù)參數(shù)的值

  • ConstructorArgumentValues resolvedValues = null;

  • boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);

  • int minTypeDiffWeight = Integer.MAX_VALUE;

  • Set<Method> ambiguousFactoryMethods = null;


  • int minNrOfArgs;

  • if (explicitArgs != null) {

  • minNrOfArgs = explicitArgs.length;

  • }

  • else {

  • // getBean() 沒有傳遞參數(shù),則需要解析保存在 BeanDefinition 構(gòu)造函數(shù)中指定的參數(shù)

  • if (mbd.hasConstructorArgumentValues()) {

  • // 構(gòu)造函數(shù)的參數(shù)

  • ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

  • resolvedValues = new ConstructorArgumentValues();

  • // 解析構(gòu)造函數(shù)的參數(shù)

  • // 將該 bean 的構(gòu)造函數(shù)參數(shù)解析為 resolvedValues 對(duì)象,其中會(huì)涉及到其他 bean

  • minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);

  • }

  • else {

  • minNrOfArgs = 0;

  • }

  • }


  • LinkedList<UnsatisfiedDependencyException> causes = null;


  • for (Method candidate : candidates) {

  • // 方法體的參數(shù)

  • Class<?>[] paramTypes = candidate.getParameterTypes();


  • if (paramTypes.length >= minNrOfArgs) {

  • // 保存參數(shù)的對(duì)象

  • ArgumentsHolder argsHolder;


  • // getBean()傳遞了參數(shù)

  • if (explicitArgs != null){

  • // 顯示給定參數(shù),參數(shù)長度必須完全匹配

  • if (paramTypes.length != explicitArgs.length) {

  • continue;

  • }

  • // 根據(jù)參數(shù)創(chuàng)建參數(shù)持有者

  • argsHolder = new ArgumentsHolder(explicitArgs);

  • }

  • else {

  • // 為提供參數(shù),解析構(gòu)造參數(shù)

  • try {

  • String[] paramNames = null;

  • // 獲取 ParameterNameDiscoverer 對(duì)象

  • // ParameterNameDiscoverer 是用于解析方法和構(gòu)造函數(shù)的參數(shù)名稱的接口,為參數(shù)名稱探測(cè)器

  • ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();

  • if (pnd != null) {

  • // 獲取指定構(gòu)造函數(shù)的參數(shù)名稱

  • paramNames = pnd.getParameterNames(candidate);

  • }



  • // 在已經(jīng)解析的構(gòu)造函數(shù)參數(shù)值的情況下,創(chuàng)建一個(gè)參數(shù)持有者對(duì)象

  • argsHolder = createArgumentArray(

  • beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);

  • }

  • catch (UnsatisfiedDependencyException ex) {

  • if (this.beanFactory.logger.isTraceEnabled()) {

  • this.beanFactory.logger.trace("Ignoring factory method [" + candidate +

  • "] of bean '" + beanName + "': " + ex);

  • }

  • if (causes == null) {

  • causes = new LinkedList<>();

  • }

  • causes.add(ex);

  • continue;

  • }

  • }


  • // isLenientConstructorResolution 判斷解析構(gòu)造函數(shù)的時(shí)候是否以寬松模式還是嚴(yán)格模式

  • // 嚴(yán)格模式:解析構(gòu)造函數(shù)時(shí),必須所有的都需要匹配,否則拋出異常

  • // 寬松模式:使用具有"最接近的模式"進(jìn)行匹配

  • // typeDiffWeight:類型差異權(quán)重

  • int typeDiffWeight = (mbd.isLenientConstructorResolution() ?

  • argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));

  • // 代表最接近的類型匹配,則選擇作為構(gòu)造函數(shù)

  • if (typeDiffWeight < minTypeDiffWeight) {

  • factoryMethodToUse = candidate;

  • argsHolderToUse = argsHolder;

  • argsToUse = argsHolder.arguments;

  • minTypeDiffWeight = typeDiffWeight;

  • ambiguousFactoryMethods = null;

  • }


  • // 如果具有相同參數(shù)數(shù)量的方法具有相同的類型差異權(quán)重,則收集此類型選項(xiàng)

  • // 但是,僅在非寬松構(gòu)造函數(shù)解析模式下執(zhí)行該檢查,并顯式忽略重寫方法(具有相同的參數(shù)簽名)

  • else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&

  • !mbd.isLenientConstructorResolution() &&

  • paramTypes.length == factoryMethodToUse.getParameterCount() &&

  • !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {


  • // 查找到多個(gè)可匹配的方法

  • if (ambiguousFactoryMethods == null) {

  • ambiguousFactoryMethods = new LinkedHashSet<>();

  • ambiguousFactoryMethods.add(factoryMethodToUse);

  • }

  • ambiguousFactoryMethods.add(candidate);

  • }

  • }

  • }


  • // 沒有可執(zhí)行的工廠方法,拋出異常

  • if (factoryMethodToUse == null) {

  • if (causes != null) {

  • UnsatisfiedDependencyException ex = causes.removeLast();

  • for (Exception cause : causes) {

  • this.beanFactory.onSuppressedException(cause);

  • }

  • throw ex;

  • }

  • List<String> argTypes = new ArrayList<>(minNrOfArgs);

  • if (explicitArgs != null) {

  • for (Object arg : explicitArgs) {

  • argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");

  • }

  • }

  • else if (resolvedValues != null){

  • Set<ConstructorArgumentValues.ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());

  • valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());

  • valueHolders.addAll(resolvedValues.getGenericArgumentValues());

  • for (ConstructorArgumentValues.ValueHolder value : valueHolders) {

  • String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :

  • (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));

  • argTypes.add(argType);

  • }

  • }

  • String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);

  • throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  • "No matching factory method found: " +

  • (mbd.getFactoryBeanName() != null ?

  • "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +

  • "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +

  • "Check that a method with the specified name " +

  • (minNrOfArgs > 0 ? "and arguments " : "") +

  • "exists and that it is " +

  • (isStatic ? "static" : "non-static") + ".");

  • }

  • else if (void.class == factoryMethodToUse.getReturnType()) {

  • throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  • "Invalid factory method '" + mbd.getFactoryMethodName() +

  • "': needs to have a non-void return type!");

  • }

  • else if (ambiguousFactoryMethods != null) {

  • throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  • "Ambiguous factory method matches found in bean '" + beanName + "' " +

  • "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +

  • ambiguousFactoryMethods);

  • }


  • if (explicitArgs == null && argsHolderToUse != null) {

  • // 將解析的構(gòu)造函數(shù)加入緩存

  • argsHolderToUse.storeCache(mbd, factoryMethodToUse);

  • }

  • }


  • try {

  • // 實(shí)例化 bean

  • Object beanInstance;


  • if (System.getSecurityManager() != null) {

  • final Object fb = factoryBean;

  • final Method factoryMethod = factoryMethodToUse;

  • final Object[] args = argsToUse;

  • // 通過執(zhí)行工廠方法來創(chuàng)建bean示例

  • beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->

  • beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args),

  • beanFactory.getAccessControlContext());

  • }

  • else {

  • // 通過執(zhí)行工廠方法來創(chuàng)建bean示例

  • beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(

  • mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);

  • }


  • // 包裝為 BeanWraper 對(duì)象

  • bw.setBeanInstance(beanInstance);

  • return bw;

  • }

  • catch (Throwable ex) {

  • throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  • "Bean instantiation via factory method failed", ex);

  • }

  • }

  • instantiateUsingFactoryMethod() 方法體實(shí)在是太大了,處理細(xì)節(jié)感覺很復(fù)雜,LZ是硬著頭皮看完的,中間斷斷續(xù)續(xù)的。吐槽這里的代碼風(fēng)格,完全不符合我們前面看的 Spring 代碼風(fēng)格。Spring 的一貫做法是將一個(gè)復(fù)雜邏輯進(jìn)行拆分,分為多個(gè)細(xì)小的模塊進(jìn)行嵌套,每個(gè)模塊負(fù)責(zé)一部分功能,模塊與模塊之間層層嵌套,上一層一般都是對(duì)下一層的總結(jié)和概括,這樣就會(huì)使得每一層的邏輯變得清晰易懂。

    回歸到上面的方法體,雖然代碼體量大,但是總體我們還是可看清楚這個(gè)方法要做的事情。一句話概括就是:確定工廠對(duì)象,然后獲取構(gòu)造函數(shù)和構(gòu)造參數(shù),最后調(diào)用 InstantiationStrategy 對(duì)象的 instantiate() 來創(chuàng)建 bean 實(shí)例。下面我們就這個(gè)句概括的話進(jìn)行拆分并詳細(xì)說明。

    確定工廠對(duì)象

    首先獲取工廠方法名,若工廠方法名不為空,則調(diào)用 beanFactory.getBean() 獲取工廠對(duì)象,若為空,則可能為一個(gè)靜態(tài)工廠,對(duì)于靜態(tài)工廠則必須提供工廠類的全類名,同時(shí)設(shè)置 factoryBean=null

    構(gòu)造參數(shù)確認(rèn)

    工廠對(duì)象確定后,則是確認(rèn)構(gòu)造參數(shù)。構(gòu)造參數(shù)的確認(rèn)主要分為三種情況:explicitArgs 參數(shù)、緩存中獲取、配置文件中解析。

    explicitArgs 參數(shù)

    explicitArgs 參數(shù)是我們調(diào)用 getBean() 時(shí)傳遞景來,一般該參數(shù),該參數(shù)就是用于初始化 bean 時(shí)所傳遞的參數(shù),如果該參數(shù)不為空,則可以確定構(gòu)造函數(shù)的參數(shù)就是它了。

    緩存中獲取

    在該方法的最后,我們會(huì)發(fā)現(xiàn)這樣一段代碼: argsHolderToUse.storeCache(mbd,factoryMethodToUse) ,這段代碼主要是將構(gòu)造函數(shù)、構(gòu)造參數(shù)保存到緩存中,如下:

  • public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {

  • synchronized (mbd.constructorArgumentLock) {

  • mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;

  • mbd.constructorArgumentsResolved = true;

  • if (this.resolveNecessary) {

  • mbd.preparedConstructorArguments = this.preparedArguments;

  • }

  • else {

  • mbd.resolvedConstructorArguments = this.arguments;

  • }

  • }

  • }

  • 其中涉及到的幾個(gè)參數(shù) constructorArgumentLock、resolvedConstructorOrFactoryMethod、constructorArgumentsResolved、resolvedConstructorArguments。這些參數(shù)都是跟構(gòu)造函數(shù)、構(gòu)造函數(shù)緩存有關(guān)的。

    constructorArgumentLock:構(gòu)造函數(shù)的緩存鎖

    resolvedConstructorOrFactoryMethod:緩存已經(jīng)解析的構(gòu)造函數(shù)或者工廠方法

    constructorArgumentsResolved:標(biāo)記字段,標(biāo)記構(gòu)造函數(shù)、參數(shù)已經(jīng)解析了。默認(rèn)為false

    resolvedConstructorArguments:緩存已經(jīng)解析的構(gòu)造函數(shù)參數(shù),包可見字段

    所以從緩存中獲取就是提取這幾個(gè)參數(shù)的值,如下:

  • synchronized (mbd.constructorArgumentLock) {

  • // 獲取緩存中的構(gòu)造函數(shù)或者工廠方法

  • factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;

  • if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {

  • // 獲取緩存中的構(gòu)造參數(shù)

  • argsToUse = mbd.resolvedConstructorArguments;

  • if (argsToUse == null) {

  • // 獲取緩存中的構(gòu)造函數(shù)參數(shù)的包可見字段

  • argsToResolve = mbd.preparedConstructorArguments;

  • }

  • }

  • }

  • 如果緩存中存在構(gòu)造參數(shù),則需要調(diào)用 resolvePreparedArguments() 方法進(jìn)行轉(zhuǎn)換,因?yàn)榫彺嬷械闹涤锌赡苁亲罱K值也有可能不是最終值,比如我們構(gòu)造函數(shù)中的類型為 Integer 類型的 1 ,但是原始的參數(shù)類型有可能是 String 類型的 1 ,所以即便是從緩存中得到了構(gòu)造參數(shù)也需要經(jīng)過一番的類型轉(zhuǎn)換確保參數(shù)類型完全對(duì)應(yīng)。

    配置文件中解析

    即沒有通過傳遞參數(shù)的方式傳遞構(gòu)造參數(shù),緩存中也沒有,那就只能通過解析配置文件獲取構(gòu)造參數(shù)了。

    在 bean 解析類的博文中我們了解了,配置文件中的信息都會(huì)轉(zhuǎn)換到 BeanDefinition 實(shí)例對(duì)象中,所以配置文件中的參數(shù)可以直接通過 BeanDefinition 對(duì)象獲取。代碼如下:

  • if (mbd.hasConstructorArgumentValues()) {

  • // 構(gòu)造函數(shù)的參數(shù)

  • ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

  • resolvedValues = new ConstructorArgumentValues();

  • // 解析構(gòu)造函數(shù)的參數(shù)

  • // 將該 bean 的構(gòu)造函數(shù)參數(shù)解析為 resolvedValues 對(duì)象,其中會(huì)涉及到其他 bean

  • minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);

  • }

  • 通過 BeanDefinition 的 getConstructorArgumentValues() 就可以獲取構(gòu)造信息了,有了構(gòu)造信息就可以獲取相關(guān)的參數(shù)值信息了,獲取的參數(shù)信息包括直接值和引用,這一步驟的處理交由 resolveConstructorArguments()完成,該方法會(huì)將構(gòu)造參數(shù)信息解析為 resolvedValues 對(duì)象 并返回解析到的參數(shù)個(gè)數(shù)。

    構(gòu)造函數(shù)

    確定構(gòu)造參數(shù)后,下一步則是確定構(gòu)造函數(shù)。第一步則是通過 getCandidateMethods() 獲取所有的構(gòu)造方法,同時(shí)對(duì)構(gòu)造方法進(jìn)行刷選,然后在對(duì)其進(jìn)行排序處理( AutowireUtils.sortFactoryMethods(candidates)),排序的主要目的是為了能夠更加方便的找到匹配的構(gòu)造函數(shù),因?yàn)闃?gòu)造函數(shù)的確認(rèn)是根據(jù)參數(shù)個(gè)數(shù)確認(rèn)的。排序的規(guī)則是:public 構(gòu)造函數(shù)優(yōu)先參數(shù)數(shù)量降序、非 public 構(gòu)造參數(shù)數(shù)量降序。

    通過迭代 candidates(包含了所有要匹配的構(gòu)造函數(shù))的方式,一次比較其參數(shù),如果顯示提供了參數(shù)(explicitArgs != null),則直接比較兩者是否相等,如果相等則表示找到了,否則繼續(xù)比較。如果沒有顯示提供參數(shù),則需要獲取 ParameterNameDiscoverer 對(duì)象,該對(duì)象為參數(shù)名稱探測(cè)器,主要用于發(fā)現(xiàn)方法和構(gòu)造函數(shù)的參數(shù)名稱。

    將參數(shù)包裝成 ArgumentsHolder 對(duì)象,該對(duì)象用于保存參數(shù),我們稱之為參數(shù)持有者。當(dāng)將對(duì)象包裝成 ArgumentsHolder 對(duì)象后,我們就可以通過它來進(jìn)行構(gòu)造函數(shù)匹配,匹配分為嚴(yán)格模式和寬松模式。

    嚴(yán)格模式:解析構(gòu)造函數(shù)時(shí),必須所有參數(shù)都需要匹配,否則拋出異常

    寬松模式:使用具有"最接近的模式"進(jìn)行匹配

    判斷的依據(jù)是根據(jù) BeanDefinition 的 isLenientConstructorResolution 屬性(該參數(shù)是我們?cè)跇?gòu)造 AbstractBeanDefinition 對(duì)象是傳遞的)來獲取類型差異權(quán)重(typeDiffWeight) 的。如果 typeDiffWeight<minTypeDiffWeight ,則代表“最接近的模式”,選擇其作為構(gòu)造函數(shù),否則只有兩者具有相同的參數(shù)數(shù)量且類型差異權(quán)重相等才會(huì)納入考慮范圍。

    至此,構(gòu)造函數(shù)已經(jīng)確認(rèn)了。

    創(chuàng)建 bean 實(shí)例

    工廠對(duì)象、構(gòu)造函數(shù)、構(gòu)造參數(shù)都已經(jīng)確認(rèn)了,則最后一步就是調(diào)用 InstantiationStrategy 對(duì)象的 instantiate() 來創(chuàng)建 bean 實(shí)例,如下:

  • public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,

  • @Nullable Object factoryBean, final Method factoryMethod, @Nullable Object... args) {


  • try {

  • if (System.getSecurityManager() != null) {

  • AccessController.doPrivileged((PrivilegedAction<Object>) () -> {

  • ReflectionUtils.makeAccessible(factoryMethod);

  • return null;

  • });

  • }

  • else {

  • ReflectionUtils.makeAccessible(factoryMethod);

  • }


  • Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();

  • try {

  • currentlyInvokedFactoryMethod.set(factoryMethod);

  • // 執(zhí)行工廠方法,并返回實(shí)例

  • Object result = factoryMethod.invoke(factoryBean, args);

  • if (result == null) {

  • result = new NullBean();

  • }

  • return result;

  • }

  • finally {

  • if (priorInvokedFactoryMethod != null) {

  • currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);

  • }

  • else {

  • currentlyInvokedFactoryMethod.remove();

  • }

  • }

  • }

  • // 省略一波 catch

  • }

  • instantiate() 最核心的部分就是利用 Java 反射執(zhí)行工廠方法并返回創(chuàng)建好的實(shí)例,也就是這段代碼:

  • Object result = factoryMethod.invoke(factoryBean, args);

  • 到這里 instantiateUsingFactoryMethod() 已經(jīng)分析完畢了,這里 LZ 有些題外話需要說下,看源碼真心是一個(gè)痛苦的過程,尤其是復(fù)雜的源碼,比如這個(gè)方法我看了三天才弄清楚點(diǎn)皮毛,當(dāng)然這里跟 LZ 的智商有些關(guān)系(智商捉急 ┭┮﹏┭┮),寫這篇博客也花了五天時(shí)間才寫完(最后截稿日為:2018.08.10 01:23:49),所以每一個(gè)堅(jiān)持寫博客的都是折翼的天使,值得各位尊敬

    createBeanInstance() 還有兩個(gè)重要方法 autowireConstructor() 和 instantiateBean() ,由于篇幅問題,所以將這兩個(gè)方法放在下篇博客分析。敬請(qǐng)期待!!!


    原文發(fā)布時(shí)間為:2018-10-31
    本文作者:Java技術(shù)驛站
    本文來自云棲社區(qū)合作伙伴“Java技術(shù)驛站”,了解相關(guān)信息可以關(guān)注“Java技術(shù)驛站”。

    總結(jié)

    以上是生活随笔為你收集整理的【死磕 Spring】—– IOC 之 Factory 实例化 bean的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 91日韩一区二区 | 国内精品人妻无码久久久影院蜜桃 | 91搞搞| 国产精品伦 | 伊人久久激情 | 欧美熟妇另类久久久久久多毛 | 亚洲一区二区三区在线视频观看 | 欧美日韩一区二区三区不卡视频 | 欧美色涩 | 免费成人福利视频 | 亚洲精品2区 | 91爱爱com| 欧美特级黄色 | 国产日韩欧美高清 | 亚洲精品a | 国产精品视频无码 | 精品国产97 | 欧美午夜一区 | 丰满熟妇人妻av无码区 | 国产免费久久 | 制服丝袜第一页在线观看 | 美攻壮受大胸奶汁(高h) | 天堂网在线最新版www中文网 | 黄色成人一级片 | 亚洲国产精品视频 | 日本性视频网站 | 日本在线免费播放 | 99久久婷婷国产综合精品草原 | 日韩在线免费观看视频 | v片在线免费观看 | 午夜精品一区二区三区免费视频 | 羞羞羞网站 | 美女被艹视频网站 | 特级西西www444人体聚色 | 不卡av片 | 五月色婷婷综合 | 高清在线一区 | 福利视频不卡 | 国产免费观看久久黄av片 | www国产亚洲精品久久网站 | 国产精品久久久久桃色tv | 爆操网站 | 丰满人妻一区二区三区大胸 | 日本视频在线看 | 亚洲精品免费在线播放 | 公侵犯一区二区三区四区中文字幕 | 无码国产精品高潮久久99 | 蜜色av| 在线成人一区二区 | 欧美在线视频a | 亲子乱对白乱都乱了 | 欧美1314| 国产日韩av在线 | 色屋永久 | 人妻少妇偷人精品久久性色 | 欧美亚洲精品在线 | 日本免费高清 | 亚洲午夜精品久久久久久人妖 | 国产又猛又黄 | 国产成人av一区二区三区不卡 | 夜夜草av | 九七av | 色婷婷av在线 | 久久日韩精品 | 日韩欧美国产高清91 | 亚洲 欧美 成人 | 色伊人| 色一情一乱一区二区三区 | h在线免费观看 | 婷婷婷色| 日韩精品卡通动漫网站 | 午夜黄色福利视频 | 欧美成人黄| 久久精品视 | 成人欧美激情 | 99午夜视频 | 国产激情久久久久久熟女老人av | 美女伦理水蜜桃4 | 91精品国产高清一区二区三密臀 | 波多野结衣www | 黄色午夜网站 | 婷婷久久五月天 | 国产精品久久综合视频 | 黄网在线| 在线成人免费 | 麻豆视频一区 | 看久久 | 三年中文在线观看免费观看 | 精品亚洲国产成人av制服丝袜 | 日韩1区2区3区 | 中文字幕在线观看你懂的 | 久久久精品久久久久久 | 色婷婷av一区二区 | av第一福利大全导航 | 亚洲在线激情 | 日韩欧美一卡二卡 | 涩涩视频网站 | 久久久蜜桃一区二区人 | 爱豆国产剧免费观看大全剧集 |