SpringにおけるBean初期化フェーズとBeanPostProcessorの動作機構

初期化フェーズにおけるフック処理の流れ

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定義を解決して注入処理を実行します。この処理はプロパティ代入ステージと初期化前後のフック点で連携しながら行われ、循環参照や型不整合のエラーハンドリングも行います。

タグ: SpringFramework BeanPostProcessor DependencyInjection DynamicProxy JakartaValidation

7月29日 02:26 投稿