A little bit of everything

元・情報系大学院生の備忘録

【まとめ】Springフレームワークにおける Bean の ライフサイクル

今後も情報が分かり次第、随時このページに情報を追加していきます!

この記事では、Spring フレームワークにおける、Java Beanのライフサイクルについてまとめます。
ここに示す内容は、Spring Boot アプリケーションにも当てはまります。
基本、こちらのページを日本語訳しつつ、少しだけ情報を付け加えています。
howtodoinjava.com

1. Bean のライフサイクル

SpringのDIコンテナ(≒IoCコンテナ)が起動すると、JavaConfig またはXMLのBean定義に基づいて、Spring Beanがインスタンス化されます。
インスタンス化はフレームワークが自動で行ってくれて、最終的にJava Beanが「使用可能な状態」になります。
この「使用可能な状態」になったJava BeanをDIコンテナが管理してくれて、プログラマが書いたコードに注入(DI)してくれるわけです。

結論から述べると、以下の図のとおりになります。
f:id:yuukiyg:20191104045012p:plain

このフローに沿ってBeanが「使用可能な状態」になると、DIコンテナがそれらのBeanを管理してくれて、プログラマが書いたコードに注入(DI)してくれます。そして、Beanが不要になると、DIコンテナから削除されます。 Spring Bean Factory は、Spring Containerを介して作成されたBeanのライフサイクルを管理します。

1.1 Beanのライフサイクルにおける独自処理を行いたい場合

Beanのライフサイクル上で、何ら化の独自処理を実行したい場合、用途に応じたコールバックメソッドが用意されているので、それを使用します。
これらのメソッドは、大きく2つのグループに分類できます。

  1. 初期化後のコールバックメソッド
  2. 破棄前のコールバックメソッド

以下で、ライフサイクル上で実行できるコールバックメソッドについて詳しく述べます。

2.コールバックメソッド

Springフレームワークは、Beanのライフサイクルイベントを制御するために次の4つの方法を提供しています。

この4つを順に説明していきます。

2.1 InitializingBeanおよびDisposableBean

org.springframework.beans.factory.InitializingBeanインターフェースを実装したクラスは、Beanのセットアップに必要なすべてのプロパティをコンテナが設定した後に行う初期化処理を定義できます。
InitializingBeanを実装したクラスでは、afterPropertiesSet()メソッドを実装する必要があります。

void afterPropertiesSet() throws Exception;     

ちなみに、InitializingBeanを使ってBeanの初期化をすることは非推奨だそうです。
その理由は、BeanクラスとSpringコンテナが密結合になるためです。

ここで言う「密結合」の意味は、BeanクラスがSpringフレームワークを使うことを前提とした作りになってしまうということだと思っています。
つまり、IoC(=Inversion of Control=制御の反転)において、Beanは「誰から使われるBeanなのか?」を気にすることなく設計すべきなのに、InitializingBeanを使うことによって、「SpringフレームワークのDIコンテナから使われるBeanである」ということが前提の作りになってしまいます。

↑の青字部分、あくまでも自分の理解なので、間違っていればご指摘いただけると幸いです。

よりBetterな代替方法は、applicationContext.xmlのBean定義で「init-method」を使用することです。

同様に、org.springframework.beans.factory.DisposableBeanインターフェースを実装すると、コンテナが破棄されるときにBeanがコールバックを取得できます。

void destroy() throws Exception;  

2.2 特定の動作をさせるための *Awareインターフェイス

Springは、Beanが特定のインフラストラクチャ依存性を必要とすることをコンテナに示すことを可能にする一連の*Awareインターフェイスを提供します。 各インターフェイスでは、Beanに依存関係を注入するメソッドを実装する必要があります。

Awareインタフェース Overrideの必要があるメソッド 目的
ApplicationContextAware void setApplicationContext (ApplicationContext applicationContext) throws BeansException; 実行されるApplicationContextの通知を希望するオブジェクトによって実装されるインターフェイス
ApplicationEventPublisherAware void setApplicationEventPublisher (ApplicationEventPublisher applicationEventPublisher); このオブジェクトが実行されるApplicationEventPublisherを設定します。
BeanClassLoaderAware void setBeanClassLoader (ClassLoader classLoader); BeanクラスローダーをBeanインスタンスに提供するコールバック。
BeanFactoryAware void setBeanFactory (BeanFactory beanFactory) throws BeansException; 所有ファクトリをBeanインスタンスに提供するコールバック。
BeanNameAware void setBeanName(String name); このBeanを作成したBeanファクトリーでBeanの名前を設定します。
BootstrapContextAware void setBootstrapContext (BootstrapContext bootstrapContext); このオブジェクトが実行されるBootstrapContextを設定します。
LoadTimeWeaverAware void setLoadTimeWeaver (LoadTimeWeaver loadTimeWeaver); このオブジェクトを含むApplicationContextのLoadTimeWeaverを設定します。
MessageSourceAware void setMessageSource (MessageSource messageSource); このオブジェクトが実行されるMessageSourceを設定します。
NotificationPublisherAware void setNotificationPublisher (NotificationPublisher notificationPublisher); 現在の管理対象リソースインスタンスのNotificationPublisherインスタンスを設定します。
PortletConfigAware void setPortletConfig (PortletConfig portletConfig); このオブジェクトが実行されるPortletConfigを設定します。
PortletContextAware void setPortletContext (PortletContext portletContext); このオブジェクトが実行されるPortletContextを設定します。
ResourceLoaderAware void setResourceLoader (ResourceLoader resourceLoader); このオブジェクトが実行されるResourceLoaderを設定します。
ServletConfigAware void setServletConfig (ServletConfig servletConfig); このオブジェクトが実行されるServletConfigを設定します。
ServletContextAware void setServletContext (ServletContext servletContext); このオブジェクトが実行されるServletContextを設定します。

2.3 独自に定義可能なinit() およびdestroy() メソッド

init()メソッドおよびdestroy()メソッドは、2つの方法で定義できます。

  • Beanローカル定義:単一のBeanに適用可能な定義方法。
  • グローバル定義:Beanコンテキストで定義されたすべてのBeanに適用可能な定義方法。

2.3.1 Beanローカル定義

<beans>
    <bean id="testBean" class="com.yuukiygTestBean"
                    init-method="customInit"
                    destroy-method="customDestroy"></bean>
</beans>

2.3.2 グローバル定義

グローバル定義は以下のとおりです。 これらのメソッドは、タグで指定されたすべてのBean定義に対して呼び出されます。 これらは、すべてのBeanに対して一貫してinit()やdestroy()などの共通メソッドを定義したい場合に使用します。また、グローバル定義を使用すると、すべてのBeanのinit()およびdestroy()メソッドの名前を個別に指定する必要がなくなります。

<beans default-init-method="customInit" default-destroy-method="customDestroy">   
        <bean id="demoBean" class="com.yuukiyg.DemoBean"></bean>
</beans>

上記のBean定義ファイルに書いたメソッド名に対して、以下のようにJavaプログラムで、そのメソッドを定義する必要がある。

public class DemoBean {
    public void customInit() {
        System.out.println("Method customInit() invoked...");
    }
 
    public void customDestroy() {
        System.out.println("Method customDestroy() invoked...");
    }
}

2.4 @PostConstructおよび@PreDestroyアノテーション

Spring 2.5以降では、@PostConstruct や @PreDestroyアノテーションを使用してライフサイクルメソッドを指定することもできます。

@PostConstructアノテーションを付与したメソッドは、デフォルトコンストラクタを使用してBeanが生成された後、そのインスタンスが他のオブジェクト(つまり、そのインスタンスを欲しがっているオブジェクト)に対してDIされる直前に呼び出されます。

@PreDestroyアノテーションを付与したメソッドは、BeanがDIコンテナ内で破棄される直前に呼び出されます。

public class DemoBean {
    @PostConstruct
    public void customInit() {
        System.out.println("Method customInit() invoked...");
    }
     
    @PreDestroy
    public void customDestroy() {
        System.out.println("Method customDestroy() invoked...");
    }
}

つづく・・・