SpringのBeanのインスタンス化

SpringのBeanのインスタンス化

SpringのBeanのインスタンス化、プロパティ注入、初期化は、doCreateBeanメソッド内で実行されます。

doCreateBeanメソッド内で、Beanのインスタンスを作成するcreateBeanInstanceメソッドが呼び出されます。

protected BeanWrapper createBeanInstance(String beansName, RootBeanDefinition bdf, @Nullable Object[] args) {
    // クラスの解決
    Class<?> beanClass = resolveBeanClass(bdf, beansName);
    // パブリックなアクセス許可がない場合、例外をスロー
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !bdf.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(bdf.getResourceDescription(), beansName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }
    // インスタンス生成用のサプライヤーが定義されている場合
    Supplier<?> instanceSupplier = bdf.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beansName);
    }
    // ファクトリーメソッドが定義されている場合
    if (bdf.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beansName, bdf, args);
    }
    
    // 類が複数のコンストラクタを持つ場合、Springは引数の個数や型に基づいてコンストラクタを選択します
    // 解析済みのコンストラクタまたはファクトリーメソッドをBeanDefinitionにキャッシュします
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (bdf.constructorArgumentLock) {
            if (bdf.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = bdf.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beansName, bdf, null, null);
        } else {
            return instantiateBean(beansName, bdf);
        }
    }

    // コンストラクタの解析を開始
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beansName);
    // コンストラクタ引数の解析が必要な場合
    if (ctors != null ||
        bdf.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
        bdf.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beansName, bdf, ctors, args);
    }

    // デフォルトコンストラクタを使用
    return instantiateBean(beansName, bdf);
}

上記のコードの論理は以下のとおりです:

  1. InstanceSupplierが定義されている場合、そのコールバックを使用してBeanを生成します。

  2. factoryMethodNameまたはfactory-methodが定義されている場合、ファクトリーメソッドを使用してBeanを生成します。

  3. 複数のコンストラクタがある場合、引数の個数や型に基づいて適切なコンストラクタを選択します。

  4. コンストラクタの解析結果をBeanDefinitionにキャッシュします。

1. 引数付きのインスタンス化

引数付きのBean生成方法は以下のとおりです:

public BeanWrapper autowireConstructor(final String beansName, final RootBeanDefinition bdf,
        @Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {
    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    Constructor<?> constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;

    // getBean時に引数が渡されている場合
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    } else {
        // キャッシュされた引数を使用
        synchronized (bdf.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bdf.resolvedConstructorOrFactoryMethod;
            if (constructorToUse != null && bdf.constructorArgumentsResolved) {
                argsToUse = bdf.resolvedConstructorArguments;
                if (argsToUse == null) {
                    argsToResolve = bdf.preparedConstructorArguments;
                }
            }
        }
        // 引数の解析を行う
        if (argsToResolve != null) {
            argsToUse = resolvePreparedArguments(beansName, bdf, bw, constructorToUse, argsToResolve);
        }
    }

    // コンストラクタが未解決の場合
    if (constructorToUse == null) {
        // 引数の個数に基づいてコンストラクタを選択
        int minNrOfArgs = (explicitArgs != null) ? explicitArgs.length : resolveConstructorArguments(beansName, bdf, bw, cargs, resolvedValues);
        // コンストラクタの候補を取得
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            candidates = (bdf.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors());
        }
        // コンストラクタをソート
        AutowireUtils.sortConstructors(candidates);

        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set<Constructor<?>> ambiguousConstructors = null;
        LinkedList<UnsatisfiedDependencyException> causes = null;

        for (Constructor<?> candidate : candidates) {
            Class<?>[] paramTypes = candidate.getParameterTypes();

            if (constructorToUse != null && argsToUse.length > paramTypes.length) {
                break;
            }
            if (paramTypes.length < minNrOfArgs) {
                continue;
            }

            // 引数の解析
            ArgumentsHolder argsHolder;
            if (resolvedValues != null) {
                String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                if (paramNames == null) {
                    ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                    if (pnd != null) {
                        paramNames = pnd.getParameterNames(candidate);
                    }
                }
                argsHolder = createArgumentArray(beansName, bdf, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring);
            } else {
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                argsHolder = new ArgumentsHolder(explicitArgs);
            }

            // 適合度の評価
            int typeDiffWeight = (bdf.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            if (typeDiffWeight < minTypeDiffWeight) {
                constructorToUse = candidate;
                argsHolderToUse = argsHolder;
                argsToUse = argsHolder.arguments;
                minTypeDiffWeight = typeDiffWeight;
                ambiguousConstructors = null;
            } else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }

        // コンストラクタが見つからない場合、例外をスロー
        if (constructorToUse == null) {
            throw new BeanCreationException(...);
        } else if (ambiguousConstructors != null && !bdf.isLenientConstructorResolution()) {
            throw new BeanCreationException(...);
        }

        // 解析結果をキャッシュ
        if (explicitArgs == null) {
            argsHolderToUse.storeCache(bdf, constructorToUse);
        }
    }

    // 実例化 chiến lượcを使用してBeanを作成
    try {
        final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
        Object beanInstance;
        if (System.getSecurityManager() != null) {
            final Constructor<?> ctorToUse = constructorToUse;
            final Object[] argumentsToUse = argsToUse;
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                    strategy.instantiate(bdf, beansName, beanFactory, ctorToUse, argumentsToUse),
                    beanFactory.getAccessControlContext());
        } else {
            beanInstance = strategy.instantiate(bdf, beansName, this.beanFactory, constructorToUse, argsToUse);
        }
        bw.setBeanInstance(beanInstance);
        return bw;
    } catch (Throwable ex) {
        throw new BeanCreationException(bdf.getResourceDescription(), beansName, "Bean instantiation failed", ex);
    }
}

2. 引数なしのインスタンス化

引数なしの場合、Beanの生成方法は以下のとおりです:

protected BeanWrapper instantiateBean(final String beansName, final RootBeanDefinition bdf) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                    getInstantiationStrategy().instantiate(bdf, beansName, parent),
                    getAccessControlContext());
        } else {
            beanInstance = getInstantiationStrategy().instantiate(bdf, beansName, parent);
        }
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    } catch (Throwable ex) {
        throw new BeanCreationException(bdf.getResourceDescription(), beansName, "Bean instantiation failed", ex);
    }
}
public Object instantiate(RootBeanDefinition bd, @Nullable String beansName, BeanFactory owner) {
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    } else {
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                } catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        return BeanUtils.instantiateClass(constructorToUse);
    } else {
        return instantiateWithMethodInjection(bd, beansName, owner);
    }
}

タグ: Spring Framework Bean Definition Instantiation Strategy

5月27日 08:25 投稿