Bean の性質のカスタマイズ
Spring Framework は、Bean の性質をカスタマイズするために使用できる多くのインターフェースを提供します。このセクションでは、次のようにグループ化します。
ライフサイクルコールバック
Bean ライフサイクルのコンテナーの管理とやり取りするために、Spring InitializingBean
および DisposableBean
インターフェースを実装できます。コンテナーは、前者の場合は afterPropertiesSet()
を、後者の場合は destroy()
を呼び出して、Bean の初期化および破棄時に Bean が特定のアクションを実行できるようにします。
JSR-250 JSR-250 アノテーションを使用したくないが、それでもカップリングを除去したい場合は、 |
内部的に、Spring Framework は BeanPostProcessor
実装を使用して、適切なメソッドを見つけて呼び出すことができるコールバックインターフェースを処理します。カスタム機能またはその他のライフサイクル動作が必要な場合、Spring はデフォルトでは提供していませんが、BeanPostProcessor
を自分で実装できます。詳細については、コンテナー拡張ポイントを参照してください。
初期化および破棄のコールバックに加えて、Spring 管理オブジェクトは Lifecycle
インターフェースを実装することもできます。これにより、これらのオブジェクトは、コンテナー自体のライフサイクルによって駆動される起動およびシャットダウンプロセスに参加できます。
このセクションでは、ライフサイクルコールバックインターフェースについて説明します。
初期化コールバック
org.springframework.beans.factory.InitializingBean
インターフェースにより、Bean は、コンテナーが Bean で必要なすべてのプロパティを設定した後に初期化作業を実行できます。InitializingBean
インターフェースは単一のメソッドを指定します:
void afterPropertiesSet() throws Exception;
InitializingBean
インターフェースはコードを Spring に不必要に結合するため、使用しないことをお勧めします。または、@PostConstruct
アノテーションを使用するか、POJO 初期化メソッドを指定することをお勧めします。XML ベースの構成メタデータの場合、init-method
属性を使用して、引数なしの void 署名を持つメソッドの名前を指定できます。Java 構成では、@Bean
の initMethod
属性を使用できます。ライフサイクルコールバックの受信を参照してください。次の例を考えてみましょう。
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
Java
Kotlin
public class ExampleBean {
public void init() {
// do some initialization work
}
}
class ExampleBean {
fun init() {
// do some initialization work
}
}
上記の例は、次の例(2 つのリストで構成されています)とほぼ同じ効果があります。
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
Java
Kotlin
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization work
}
}
ただし、前述の 2 つの例の最初の例では、コードを Spring に結合していません。
非同期データベース準備手順など、コストのかかる初期化後のアクティビティがトリガーされるシナリオでは、Bean は あるいは、 |
破棄コールバック
org.springframework.beans.factory.DisposableBean
インターフェースを実装すると、Bean を含むコンテナーが破棄されたときに Bean がコールバックを取得できます。DisposableBean
インターフェースは単一のメソッドを指定します:
void destroy() throws Exception;
DisposableBean
コールバックインターフェースは、コードを Spring に不必要に結合するため、使用しないことをお勧めします。または、@PreDestroy
アノテーションを使用するか、Bean 定義でサポートされている一般的なメソッドを指定することをお勧めします。XML ベースの構成メタデータを使用すると、<bean/>
の destroy-method
属性を使用できます。Java 構成では、@Bean
の destroyMethod
属性を使用できます。ライフサイクルコールバックの受信を参照してください。次の定義を考慮してください。
<bean id="exampleDestructionBean" class="examples.ExampleBean" destroy-method="cleanup"/>
Java
Kotlin
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
class ExampleBean {
fun cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
上記の定義は、次の定義とほぼ同じ効果があります。
<bean id="exampleDestructionBean" class="examples.AnotherExampleBean"/>
Java
Kotlin
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (like releasing pooled connections)
}
}
ただし、前述の 2 つの定義の最初のものは、コードを Spring に結合しません。
Spring は、パブリック close
または shutdown
メソッドを検出する、destroy メソッドの推論もサポートしていることに注意してください。これは、Java 構成クラスの @Bean
メソッドのデフォルトの動作であり、java.lang.AutoCloseable
または java.io.Closeable
実装と自動的に一致し、破棄ロジックを Spring に結合しません。
XML を使用した destroy メソッド推論の場合、<bean> 要素の destroy-method 属性に特別な (inferred) 値を割り当てることができます。これにより、特定の Bean 定義の Bean クラスのパブリック close または shutdown メソッドを自動的に検出するように Spring に指示されます。この特別な (inferred) 値を <beans> 要素の default-destroy-method 属性に設定して、この動作を Bean 定義のセット全体に適用することもできます ( デフォルトの初期化および破棄メソッドを参照)。 |
延長されたシャットダウンフェーズでは、 |
デフォルトの初期化および破棄メソッド
初期化を記述し、Spring 固有の InitializingBean
および DisposableBean
コールバックインターフェースを使用しないメソッドコールバックを破棄する場合、通常は init()
、initialize()
、dispose()
などの名前のメソッドを記述します。理想的には、このようなライフサイクルコールバックメソッドの名前はプロジェクト全体で標準化され、すべての開発者が同じメソッド名を使用して一貫性を確保できるようにします。
すべての Bean の名前付き初期化を「検索」し、コールバックメソッド名を破棄するように Spring コンテナーを構成できます。これは、アプリケーション開発者が、各 Bean 定義で init-method="init"
属性を構成することなく、アプリケーションクラスを作成し、init()
と呼ばれる初期化コールバックを使用できることを意味します。Spring IoC コンテナーは、Bean の作成時に ( 前述の標準ライフサイクルコールバック契約に従って) そのメソッドを呼び出します。この機能は、初期化および破棄メソッドのコールバックに対して一貫した命名規則も適用します。
初期化コールバックメソッドの名前が init()
で、破棄コールバックメソッドの名前が destroy()
であるとします。クラスは、次の例のクラスに似ています。
Java
Kotlin
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
次に、そのクラスを次のような Bean で使用できます。
<beans default-init-method="init">
<bean id="blogService" class="com.something.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
最上位の <beans/>
要素属性に default-init-method
属性が存在すると、Spring IoC コンテナーは、Bean クラスの init
と呼ばれるメソッドを初期化メソッドコールバックとして認識します。Bean が作成およびアセンブルされるときに、Bean クラスにそのようなメソッドがある場合、適切なタイミングで呼び出されます。
最上位の <beans/>
要素で default-destroy-method
属性を使用することで、同様に(つまり XML で)destroy メソッドコールバックを構成できます。
既存の Bean クラスには、慣例とは異なる名前のコールバックメソッドがすでに存在する場合、<bean/>
自体の init-method
および destroy-method
属性を使用してメソッド名を(XML で)指定することにより、デフォルトをオーバーライドできます。
Spring コンテナーは、Bean にすべての依存関係が提供された直後に、構成された初期化コールバックが呼び出されることを保証します。初期化コールバックは生の Bean 参照で呼び出されます。これは、AOP インターセプターなどがまだ Bean に適用されていないことを意味します。ターゲット Bean が最初に完全に作成され、次にインターセプターチェーンを備えた AOP プロキシ(たとえば)が適用されます。ターゲット Bean とプロキシが別々に定義されている場合、コードはプロキシをバイパスして生のターゲット Bean と対話することさえできます。インターセプターを init
メソッドに適用することは一貫性がありません。これを行うと、ターゲット Bean のライフサイクルがそのプロキシまたはインターセプターに結合され、コードが生のターゲット Bean と直接対話するときに奇妙なセマンティクスが残るためです。
ライフサイクルメカニズムの組み合わせ
Spring 2.5 以降、Bean ライフサイクルの動作を制御するための 3 つのオプションがあります。
InitializingBean
およびDisposableBean
コールバックインターフェースカスタム
init()
およびdestroy()
メソッド@PostConstruct
および@PreDestroy
アノテーションこれらのメカニズムを組み合わせて、特定の Bean を制御できます。
1 つの Bean に対して複数のライフサイクルメカニズムが構成されており、各メカニズムが異なるメソッド名で構成されている場合、構成された各メソッドは、この注記の後にリストされている順序で実行されます。ただし、これらのライフサイクルメカニズムの複数に対して同じメソッド名が構成されている場合 (たとえば、初期化メソッドの init() )、前のセクションで説明したように、そのメソッドは 1 回実行されます。 |
同じ Bean に対して、異なる初期化方法で構成された複数のライフサイクルメカニズムは、次のように呼び出されます。
@PostConstruct
アノテーションが付けられたメソッドInitializingBean
コールバックインターフェースによって定義されたafterPropertiesSet()
カスタム構成の
init()
メソッド
Destroy メソッドは同じ順序で呼び出されます:
@PreDestroy
アノテーションが付けられたメソッドDisposableBean
コールバックインターフェースによって定義されたdestroy()
カスタム構成の
destroy()
メソッド
起動とシャットダウンのコールバック
Lifecycle
インターフェースは、独自のライフサイクル要件を持つオブジェクト(バックグラウンドプロセスの開始や停止など)に不可欠なメソッドを定義します。
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
Spring で管理されるオブジェクトは、Lifecycle
インターフェースを実装できます。次に、ApplicationContext
自体が(たとえば、実行時の停止 / 再起動シナリオのために)開始および停止シグナルを受信すると、それらの呼び出しをそのコンテキスト内で定義されたすべての Lifecycle
実装にカスケードします。これを行うには、次のリストに示す LifecycleProcessor
に委譲します。
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
LifecycleProcessor
自体が Lifecycle
インターフェースの拡張であることに注意してください。また、リフレッシュおよび閉じられるコンテキストに反応するための 2 つの他のメソッドを追加します。
通常の また、停止通知が破棄される前に送信されるとは限りません。通常のシャットダウンでは、すべての |
起動とシャットダウンの呼び出しの順序は重要です。2 つのオブジェクト間に「依存」関連が存在する場合、依存側は依存関連の後に開始し、依存関連の前に停止します。ただし、直接的な依存関連が不明な場合があります。特定の型のオブジェクトは、別の型のオブジェクトよりも先に開始する必要があることを知っているかもしれません。そのような場合、SmartLifecycle
インターフェースは別のオプション、つまりスーパーインターフェース Phased
で定義されている getPhase()
メソッドを定義します。次のリストは、Phased
インターフェースの定義を示しています。
public interface Phased {
int getPhase();
}
次のリストは、SmartLifecycle
インターフェースの定義を示しています。
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
開始時に、最も低いフェーズのオブジェクトが最初に開始されます。停止するときは、逆の順序に従います。SmartLifecycle
を実装し、getPhase()
メソッドが Integer.MIN_VALUE
を返すオブジェクトは、最初に開始し、最後に停止するオブジェクトになります。スペクトルのもう一方の端では、Integer.MAX_VALUE
の位相値は、オブジェクトが最後に開始され、最初に停止されることを示します(実行されている他のプロセスに依存するため)。位相値を検討する場合、SmartLifecycle
を実装しない「通常の」 Lifecycle
オブジェクトのデフォルトの位相が 0
であることを知ることも重要です。負の位相値は、オブジェクトがそれらの標準コンポーネントの前に開始する(およびその後に停止する)ことを示します。正の位相値の場合、逆のことが言えます。
SmartLifecycle
によって定義された停止メソッドは、コールバックを受け入れます。実装は、その実装のシャットダウンプロセスが完了した後に、そのコールバックの run()
メソッドを呼び出す必要があります。LifecycleProcessor
インターフェースのデフォルト実装である DefaultLifecycleProcessor
は、各フェーズ内のオブジェクトのグループのタイムアウト値まで待機してコールバックを呼び出すため、必要に応じて非同期シャットダウンが可能になります。デフォルトのフェーズごとのタイムアウトは 30 秒です。コンテキスト内で lifecycleProcessor
という名前の Bean を定義することにより、デフォルトのライフサイクルプロセッサーインスタンスをオーバーライドできます。タイムアウトのみを変更する場合は、次を定義するだけで十分です。
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
前に記述されていたように、LifecycleProcessor
インターフェースは、コンテキストのリフレッシュとクローズのコールバックメソッドも定義します。後者は、stop()
が明示的に呼び出されたかのようにシャットダウンプロセスを駆動しますが、コンテキストが閉じるときに発生します。一方、"refresh" コールバックは、SmartLifecycle
Bean の別の機能を有効にします。コンテキストがリフレッシュされると(すべてのオブジェクトがインスタンス化および初期化された後)、そのコールバックが呼び出されます。その時点で、デフォルトのライフサイクルプロセッサーは、各 SmartLifecycle
オブジェクトの isAutoStartup()
メソッドによって返されるブール値をチェックします。true
の場合、そのオブジェクトはコンテキストまたは独自の start()
メソッドの明示的な呼び出しを待つのではなく、その時点で開始されます(コンテキストのリフレッシュとは異なり、コンテキスト開始は標準コンテキスト実装では自動的に行われません)。phase
値と「依存」関連により、前述のように起動順序が決まります。
非 Web アプリケーションで Spring IoC コンテナーを正常にシャットダウンする
このセクションは、非 Web アプリケーションにのみ適用されます。Spring の Web ベースの |
Spring の IoC コンテナーを非 Web アプリケーション環境(たとえば、リッチクライアントデスクトップ環境)で使用する場合、シャットダウンフックを JVM に登録します。これにより、正常なシャットダウンが保証され、シングルトン Bean の関連する destroy メソッドが呼び出され、すべてのリソースが解放されます。これらの破棄コールバックを正しく構成および実装する必要があります。
シャットダウンフックを登録するには、次の例に示すように、ConfigurableApplicationContext
インターフェースで宣言されている registerShutdownHook()
メソッドを呼び出します。
Java
Kotlin
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}
import org.springframework.context.support.ClassPathXmlApplicationContext
fun main() {
val ctx = ClassPathXmlApplicationContext("beans.xml")
// add a shutdown hook for the above context...
ctx.registerShutdownHook()
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
スレッドの安全性と可視性
Spring コアコンテナーは、作成されたシングルトンインスタンスをスレッドセーフな方法で公開し、シングルトンロックを通じてアクセスを保護し、他のスレッドでの可視性を保証します。
結果として、アプリケーションが提供する Bean クラスは、初期化状態の可視性を考慮する必要がありません。通常の構成フィールドは、初期化フェーズ中にのみ変更される限り、volatile
としてマークされる必要はありません。初期フェーズ中に変更可能な setter ベースの構成状態であっても、final
と同様の可視性が保証されます。このようなフィールドが Bean 作成フェーズおよびその後の最初の公開後に変更された場合、volatile
として宣言されるか、アクセスされるたびに共通ロックによって保護される必要があります。
シングルトン Bean インスタンス (コントローラーインスタンスやリポジトリインスタンスなど) 内のこのような構成状態への同時アクセスは、コンテナー側からの安全な初期公開後は完全にスレッドセーフであることに注意してください。これには、一般的なシングルトンロック内で処理される一般的なシングルトン FactoryBean
インスタンスも含まれます。
破棄コールバックの場合、構成状態はスレッドセーフのままですが、初期化と破棄の間に蓄積されたランタイム状態は、一般的な Java ガイドラインに従ってスレッドセーフ構造 (または単純な場合は volatile
フィールド) に保持される必要があります。
上に示したように、より深い Lifecycle
統合には、volatile
として宣言する必要がある runnable
フィールドなどの実行時に変更可能な状態が含まれます。共通のライフサイクルコールバックは特定の順序に従いますが、たとえば、開始コールバックは完全な初期化の後にのみ発生し、停止コールバックは最初の開始の後にのみ発生することが保証されていますが、共通の破棄前の停止の配置には特別なケースがあります。このような Bean の内部状態では、先行する停止なしで即時の破棄コールバックも許可することを強くお勧めします。これは、キャンセルされたブートストラップ後の異常なシャットダウン中、または別の Bean によって引き起こされた停止タイムアウトの場合に発生する可能性があるためです。
ApplicationContextAware
および BeanNameAware
ApplicationContext
が org.springframework.context.ApplicationContextAware
インターフェースを実装するオブジェクトインスタンスを作成すると、インスタンスにはその ApplicationContext
への参照が提供されます。次のリストは、ApplicationContextAware
インターフェースの定義を示しています。
public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
Bean は、ApplicationContext
インターフェースを介して、またはこのインターフェースの既知のサブクラス(追加機能を公開する ConfigurableApplicationContext
など)への参照をキャストすることにより、作成した ApplicationContext
をプログラムで操作できます。1 つの用途は、他の Bean のプログラムによる取得です。この機能が役立つ場合があります。ただし、コードを Spring に結合し、コラボレーターがプロパティとして Bean に提供される Inversion of Control スタイルには従わないため、通常は回避する必要があります。ApplicationContext
の他のメソッドは、ファイルリソースへのアクセス、アプリケーションイベントの公開、MessageSource
へのアクセスを提供します。これらの追加機能については、ApplicationContext
の追加機能で説明しています。
オートワイヤーは、ApplicationContext
への参照を取得する別の代替手段です。従来の constructor
および byType
オートワイヤーモード(オートワイヤーのコラボレーターで説明)は、それぞれコンストラクター引数または setter メソッドパラメーターに対して型 ApplicationContext
の依存関係を提供できます。フィールドや複数のパラメーターメソッドをオートワイヤーする機能など、柔軟性を高めるには、アノテーションベースのオートワイヤー機能を使用します。使用すると、ApplicationContext
は、問題のフィールド、コンストラクター、メソッドが @Autowired
アノテーションを保持している場合、ApplicationContext
型を予期するフィールド、コンストラクター引数、メソッドパラメーターに自動接続されます。詳細については、@Autowired
の使用を参照してください。
ApplicationContext
が org.springframework.beans.factory.BeanNameAware
インターフェースを実装するクラスを作成すると、そのクラスには、関連するオブジェクト定義で定義された名前への参照が提供されます。次のリストは、BeanNameAware インターフェースの定義を示しています。
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
コールバックは、通常の Bean プロパティの設定後、InitializingBean.afterPropertiesSet()
やカスタム init メソッドなどの初期化コールバックの前に呼び出されます。
その他の Aware
インターフェース
ApplicationContextAware
および BeanNameAware
(前述)に加えて、Spring は、Bean が特定のインフラストラクチャ依存性を必要とすることをコンテナーに示すことができる、広範囲の Aware
コールバックインターフェースを提供します。一般的なルールとして、名前は依存関係の型を示します。次の表に、最も重要な Aware
インターフェースを要約します。
名前 | 注入された依存関係 | 説明… |
---|---|---|
|
| |
| 包含 | |
| Bean クラスをロードするために使用されるクラスローダー。 | |
|
| |
| 宣言する Bean の名前。 | |
| ロード時にクラス定義を処理するためのウィーバーを定義しました。 | |
| メッセージを解決するための設定された戦略 (パラメーター化と国際化のサポート付き)。 | |
| Spring JMX 通知パブリッシャー。 | |
| リソースへの低レベルアクセス用に構成されたローダー。 | |
| コンテナーが実行される現在の | |
| コンテナーが実行される現在の |
これらのインターフェースを使用すると、コードが Spring API に結び付けられ、Inversion of Control スタイルに従っていません。その結果、コンテナーへのプログラムによるアクセスを必要とするインフラストラクチャ Bean にお勧めします。