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);
}
上記のコードの論理は以下のとおりです:
-
InstanceSupplierが定義されている場合、そのコールバックを使用してBeanを生成します。 -
factoryMethodNameまたはfactory-methodが定義されている場合、ファクトリーメソッドを使用してBeanを生成します。 -
複数のコンストラクタがある場合、引数の個数や型に基づいて適切なコンストラクタを選択します。
-
コンストラクタの解析結果を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);
}
}