初期化フェーズにおけるフック処理の流れ
Beanのインスタンス生成およびプロパティバインディング(populateBean)が完了すると、Springコンテナは初期化ステージへ遷移します。この段階ではinitializeBeanメソッドが中枢として機能し、登録済みのBeanPostProcessor実装に対して拡張ポイントの呼び出しを行います。
protected Object executeInitializationPhase(String beanName, Object instance, @Nullable RootBeanDefinition definition) {
// SecurityContext対応のAware系インターフェース呼び出し
invokeAwareHooks(beanName, instance);
Object processedInstance = instance;
if (isStandardBeanDefinition(definition)) {
// 初期化前のカスタム処理フック
processedInstance = invokePreInitializationCallbacks(processedInstance, beanName);
}
try {
// 明示的なinit-methodまたはInitializingBeanの実行
runCustomInitMethods(beanName, processedInstance, definition);
} catch (Throwable lifecycleError) {
throw new BeanCreationException("Bean初期化プロセスで例外が発生しました", lifecycleError);
}
if (isStandardBeanDefinition(definition)) {
// 初期化後のカスタム処理フック
processedInstance = invokePostInitializationCallbacks(processedInstance, beanName);
}
return processedInstance;
}
事前初期化フックの走査ロジック
フックループでは、コンテナに登録されたすべてのBeanPostProcessorを反復処理します。各プロセスのpostProcessBeforeInitializationメソッドが逐次呼び出され、返値がnullとなった時点で処理列を中断し、現在のインスタンスを返却する仕様になっています。
public Object runPreInitializationCallbacks(Object currentBean, String identifier) throws BeansException {
Object resultObject = currentBean;
Iterator<BeanPostProcessor> processorIter = resolveRegisteredProcessors().iterator();
while (processorIter.hasNext()) {
BeanPostProcessor currentProcessor = processorIter.next();
resultObject = currentProcessor.processBeforeInit(resultObject, identifier);
if (resultObject == null) {
break;
}
}
return resultObject;
}
主要な組み込み実装クラスの特徴
1. AsyncAnnotationBeanPostProcessor
@EnableAsyncの有効化に伴い登録され、非同期メソッド実行のための動的プロキシを生成します。Beanの初期化完了直後に呼ばれるpostProcessAfterInitialization内で、対象クラスが対象条件に合致するか検証し、一致すれば新しいプロキシビルダーを構築して戻り値として返します。
public Object applyAfterInitEnhancement(Object targetBean, String componentName) {
if (aspectAdvisor == null || targetBean instanceof AopInfrastructureBean) {
return targetBean;
}
if (targetBean instanceof Advised) {
AdvisedConfiguration config = (Advised) targetBean;
if (!config.isLocked() && validateTargetClass(targetBean)) {
addAdvisorToExistingChain(config, aspectAdvisor);
return targetBean;
}
}
if (validateForProxyGeneration(targetBean, componentName)) {
ProxyBuilder factory = createProxyFactory(targetBean);
configureProxyStrategies(factory);
factory.addAdvice(aspectAdvisor);
return factory.build(getClassLoader());
}
return targetBean;
}
2. ApplicationContextAwareProcessor
ApplicationContextAwareインターフェースを実装したクラスに対し、親コンテナ自身を自動で注入するための_processorです。これにより、任意のコンポーネントからグローバルなコンテナ状態や他のBeanの解決を可能にします。
@Component
public class ContainerAccessor implements ApplicationContextAware {
private static ApplicationContext globalContext;
@Override
public void setContext(ApplicationContext ctx) {
globalContext = ctx;
}
public static ApplicationContext getContext() {
return globalContext;
}
public static <T> T resolve(Class<T> type) {
return globalContext.getBean(type);
}
}
3. BeanValidationPostProcessor
外部からの入力データ(Controller引数、DTO、RequestBodyなど)に対してJSR-380(Jakarta Validation)準拠の制約検査を適用します。初期化フェーズ中にバリデーションルールを反映したラッパーやプロキシを構成し、不正なデータ流入を早期に検知します。
4. InitDestroyAnnotationBeanPostProcessor
@PostConstructおよび@PreDestroyなどの標準ライフサイクルアノテーションに対応します。リフレクションを用いてクラス内の注釈メタデータを収集し、初期化前後の適切なタイミングで対象メソッドを実行します。
public Object triggerLifecycleAnnotations(Object targetInstance, String id) throws BeansException {
MetadataCollector metadata = collectAnnotatedMethods(targetInstance.getClass());
try {
for (LifecycleMethod method : metadata.getInitBindings()) {
ReflectionUtils.invoke(method.getTarget(), targetInstance);
}
return targetInstance;
} catch (ReflectiveOperationException ex) {
throw new BeanCreationException("ライフサイクルメソッド実行エラー", ex);
}
}
5. AutowiredAnnotationBeanPostProcessor
依存性注入の要となる Processor です。フィールド、メソッドパラメータ、コンストラクタに付与された@Autowiredを検出し、コンテナ内の対応するBean定義を解決して注入処理を実行します。この処理はプロパティ代入ステージと初期化前後のフック点で連携しながら行われ、循環参照や型不整合のエラーハンドリングも行います。