http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ をテキトーに訳した。Spring Framework Reference Documentation 4.1.5のIII. Core Technologies 5.4.5までをテキトーに訳した - kagamihogeの日記の続き。
今度はmanaged-
の訳が管理とかマネージドとかにブレ出す。
5.4.6 Method injection
多くのアプリケーションにおいてコンテナ内のビーンはシングルトンです。あるシングルトンビーンが別のシングルトンビーンと協調したい場合、もしくは、非シングルトンビーンが別の非シングルトンビーンと協調したい場合、通常はプロパティとしてビーン定義をすることで依存性を扱います。ビーンのライフサイクルが異なると問題が発生します。いま、シングルトンビーンAが非シングルトン(プロトタイプ)ビーンBを使用したいと仮定すると、Aのメソッド呼び出しをすることになります。コンテナは一度だけシングルトンビーンAを生成するので、プロパティの設定も一度だけとなります。Aを呼び出さす度に毎回Bの新規インスタンスを設定したAのインスタンスを、コンテナは得られません。
解決策としては制御の反転が行われる前に処理を行うようにします。ApplicationContextAware
を実装することで、コンテナはビーンAをawareに出来*1て、ビーンAがビーンBと必要とする度にビーンBのインスタンス(大抵は新規のインスタンスを)を要求するようなgetBean("B")をコンテナに指示できます。以下はこの方法のサンプルです。
// a class that uses a stateful Command-style class to perform some processing package fiona.apple; // Spring-API imports import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; public Object process(Map commandState) { // grab a new instance of the appropriate Command Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } protected Command createCommand() { // notice the Spring API dependency! return this.applicationContext.getBean("command", Command.class); } public void setApplicationContext( ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
上記のコードは望ましくなく、なぜならビジネスコードがSpring Frameworkに密結合するためです。Method Injectionは、Spring IoCコンテナのいくつかの高度な機能により、より洗練した方法で上記の場合を扱えます。
Method Injectionの動機についてはこのブログエントリを読んでください。
Lookup method injection
Lookup method injectionとは、コンテナ内の別のネームドビーンをルックアップ結果として返すように、コンテナ管理ビーン(container managed beans)のメソッド呼び出しをオーバーライドするためのコンテナの機能です。ルックアップには以前のセクションで解説したシナリオにおけるプロトタイプビーンを含みます。Spring Frameworkは、このLookup method injectionの実装には、メソッドをオーバーライドするサブクラスを動的に生成するためのCGLIBライブラリが生成するバイトコードを使用します。
動的サブクラスを動作させるには、Springコンテナはfinal
が付いたクラスをサブクラス化出来ず、同様に、final
が付いたメソッドもオーバーライド出来ません。また、abstract
メソッドを持つクラスのテストにはサブクラスを自前で用意し、abstract
メソッドのスタブ実装を作る必要があります。さらに、Lookup method injectionのターゲットとなるオブジェクトはシリアライズ出来ません。Spring 3.2ではCGLIBをクラスパスに追加する必要が無くなり、その理由は、CGLIBクラスはorg.springframework下に再パッケージ化されてspring-core JAR内に同梱するようになったためです。これは便宜上だけでなく、他プロジェクトがCGLIBの別バージョンを使用することによる潜在的な衝突を避けられる利点もあります。
前述のコード例のCommandManager
クラスを参考に、SpringコンテナがcreateCommand()
メソッドの実装を動的にオーバライドするようにしてみます。CommandManager
クラスはSpringへの依存性がなくなります。
package fiona.apple; // no more Spring imports! public abstract class CommandManager { public Object process(Object commandState) { // grab a new instance of the appropriate Command interface Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } // okay... but where is the implementation of this method? protected abstract Command createCommand(); }
インジェクト用のメソッドを持つクライアントクラス(このケースではCommandManager
)では、インジェクト用のメソッドは以下の形式のシグネチャに従う必要があります。
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
メソッドがabstract
の場合、動的生成サブクラスがそのメソッドを実装します。abstract
でない場合、動的生成サブクラスはオリジナルクラスのメソッドをオーバーライドします。
<!-- a stateful bean deployed as a prototype (non-singleton) --> <bean id="command" class="fiona.apple.AsyncCommand" scope="prototype"> <!-- inject dependencies here as required --> </bean> <!-- commandProcessor uses statefulCommandHelper --> <bean id="commandManager" class="fiona.apple.CommandManager"> <lookup-method name="createCommand" bean="command"/> </bean>
commandManagerビーンは、commandビーンの新規インスタンスが必要になる度に、自身のcreateCommand()
を呼び出します。もしその必要があれば、command
ビーンはプロトタイプとしてデプロイする必要があることに注意してください*2。シングルトンとしてデプロイする場合、毎回同一のcommand
ビーンインスタンスが返されます。
注意深い読者は(org.springframework.beans.factory.config
パッケージの)ServiceLocatorFactoryBean
が使えることを発見するかもしれません。ServiceLocatorFactoryBeanのアプローチは別のユーティリティクラスObjectFactoryCreatingFactoryBean
と似ていますが、Spring固有のルックアップインタフェースではなく自前のルックアップインタフェースを指定できます。詳細については対象クラスのjavadocを参照してください。
Arbitrary method replacement
lookup method Injectionよりも使う機会の少ないと思われるmethod injectionの形態として、管理ビーンの任意のメソッドを別のメソッド実装で置き換える方法があります。この機能が実際に必要になるまで残りの部分は読み飛ばしても構いません。
XML設定メタデータでは、既存のメソッド実装を別途デプロイしたビーンで置き換えるのに、replaced-method
要素を使用します。以下のクラスを例に、computeValueメソッドをオーバーライドしたいとします。
public class MyValueCalculator { public String computeValue(String input) { // some real code... } // some other methods... }
org.springframework.beans.factory.support.MethodReplacer
インタフェースの実装して新しいメソッド定義を行います。
/** * MyValueCalculatorのcomputeValue(String)をオーバーライドするのに使用。 */ public class ReplacementComputeValue implements MethodReplacer { public Object reimplement(Object o, Method m, Object[] args) throws Throwable { // get the input value, work with it, and return a computed result String input = (String) args[0]; ... return ...; } }
基となるクラスをデプロイしてメソッドオーバーライドを指定するビーン定義は以下のようになります。
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator"> <!-- arbitrary method replacement --> <replaced-method name="computeValue" replacer="replacementComputeValue"> <arg-type>String</arg-type> </replaced-method> </bean> <bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
オーバーライドするメソッドのシグネチャを指定するために<replaced-method/>
要素内に一つ以上の<arg-type/>
要素を持てます。引数のシグネチャはクラス内にオーバーライド候補が複数ある場合に限り必要です。便宜上、引数の型文字列は完全修飾型名のサブストリングでも構いません。たとえば、以下はすべてjava.lang.String
にマッチします。
java.lang.String String Str
大抵の場合は引数の数だけで識別には十分なため、タイプ数を節約出来、引数型にマッチする短縮文字列だけで問題ありません。
5.5 Bean scopes
ビーン定義の作成時には、そのビーン定義のクラスの実インスタンスを生成するためのレシピ(recipe)を作ります。ビーン定義がレシピであるという考え方は重要で、その理由は、クラス同様に、単一のレシピから多数のインスタンスを生成可能である、という意味だからです。
設定で制御可能なのは、各種の依存性および個々のビーン定義が生成するオブジェクトに組み込まれる設定値だけでなく、個々のビーン定義が生成するオブジェクトのスコープ(scope)も制御可能です。この方法は、
Javaクラスレベルのオブジェクトスコープでbakeする代わりに*3、設定経由で生成するオブジェクトスコープを選択可能という点で、強力かつ柔軟です。ビーンはいくつかのスコープのうち一つでデプロイするように定義可能です。特に追加設定は必要なく、Spring Frameworkは5つのスコープをサポートしており、そのうち三つはweb-aware ApplicationContext
でのみ利用可能です。
以下のスコープをデフォルトでサポートしています。また、カスタムスコープを作成可能です。
Table 5.3. Bean scopes
Scope | Description |
---|---|
singleton | (デフォルト)Spring IoCコンテナごとに一つのビーン定義を単一のオブジェクトインスタンススコープにする。 |
prototype | 一つのビーン定義を任意数のオブジェクトインスタンススコープにする。 |
request | 一つのビーン定義を単一HTTPリクエストのライフサイクルスコープにする。つまり、HTTPリクエストごとに固有のビーンを持ちます*4。web-aware Spring ApplicationContext コンテキストでのみ有効です。 |
session | 一つのビーン定義をHTTP Session のライフサイクルスコープにします。web-aware Spring ApplicationContext コンテキストでのみ有効です。 |
global session | 一つのビーン定義をグローバルHTTP Session のライフサイクルにします。通常、ポートレットコンテキストで使用する場合にだけ有効です。web-aware Spring ApplicationContext コンテキストでのみ有効です。 |
application | 一つのビーン定義をServletContext のライフサイクルにします。web-aware Spring ApplicationContext コンテキストでのみ有効です。 |
Spring 3.0では、スレッドスコープ(thread scope)が利用可能ですが、デフォルトでは登録されていません。詳細については、SimpleThreadScope
のドキュメントを参照してください。スレッドスコープや他のカスタムスコープの登録方法については、the section called “Using a custom scope”を参照してください。
5.5.1 The singleton scope
シングルトンビーンのただ一つの共有(shared )インスタンスが管理対象となり、ビーン定義にマッチするidもしくはidを使用したビーンへの全リクエストに対して、Springコンテナは特定の一つのビーンを返します。
別の言い方をすると、ビーンを定義してスコープをシングルトンにすると、Spring IoCコンテナはそのビーン定義が示すオブジェクトのインスタンスをただ一つだけ(exactly one)生成します。このシングルインスタンスはシングルトンビーンなどのキャッシュに格納され、ネームドビーンでの、以降の全リクエストと参照(all subsequent requests and references)はキャッシュオブジェクトを返します。
Figure 5.2.
シングルトンビーンのSpringでの考え方はGang of Four (GoF)本が定義するSingletonパターンとは異なります。GoF Singletonはクラスローダーごとに(per ClassLoader)生成される唯一の(one and only one)インスタンスのスコープをハードコードします。Springシングルトンのスコープを端的に言い表すとすれば、コンテナごと、かつ、ビーンごと(per container and per bean)、になります。この意味は、一つのSpringコンテナ上でクラスのビーンを定義するとき、Springコンテナはビーン定義のクラスのインスタンスをただ一つだけ(one and only one)生成します。Springではシングルトンスコープがデフォルトスコープです(The singleton scope is the default scope in Spring)。XMLでシングルトンとしてビーンを定義するには、以下のように記述します。
<bean id="accountService" class="com.foo.DefaultAccountService"/> <!-- 下は冗長な記述だが、上と下は同等 (デフォルトはシングルトンスコープ) --> <bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>
5.5.2 The prototype scope
ビーンデプロイに非シングルトンのプロトタイプスコープを使用すると、指定ビーンを使用するリクエストが来るたびに新規のビーンインスタンスを生成(creation of a new bean instance)します。対象ビーンが別のビーンにインジェクトされる場合や、コンテナ上でgetBean()
メソッドを呼び出すリクエストをする場合などが該当します。一般には、ステートフルビーンにはプロトタイプスコープ、ステートレスビーンにはシングルトンスコープを使います。
以下の図はSpringのプロトタイプスコープを示してます。
一般的なDAOは対話的状態(conversational state)を一切持たないため、データアクセスオブジェクト(DAO)は一般的にはプロトタイプとして設定しません。以下の図はシングルトンで使った図をコピペしていますが、それは単に著者が手抜きをしただけです。( A data access object (DAO) is not typically configured as a prototype, because a typical DAO does not hold any conversational state; it was just easier for this author to reuse the core of the singleton diagram)*5
Figure 5.3.
XMLでプロトタイプとしてビーンを定義する例は以下の通りです。
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>
他のスコープとは対照的に、Springはプロトタイプビーンのライフサイクルを完全には管理しません。コンテナはプロトタイプオブジェクトを、インスタンス化・設定・諸々のアセンブルをしてクライアントに渡しますが、プロトタイプインスタンスに関するそれ以上の記録は行いません。それ故に、initializationライフサイクルコールバックはすべてのスコープの全オブジェクトで呼ばれますが、プロトタイプの場合、設定したdestruction
ライフサイクルコールバックは呼び出されません。クライアントコードは、プロトタイプスコープオブジェクトのクリーンナップと、プロトタイプビーンが持つ希少リソースを解放する責任があります。プロトタイプスコープビーンが抱えるリソースを解放するためにSpringコンテナを取得するには、クリーンナップの必要があるビーンの参照を持つカスタムbean post-processorの使用を検討してください。
いくつかの点において、プロトタイプスコープのビーンに関するSpringコンテナの役割はJavaのnew
演算子の代わりとなるものです。あるポイントを越えたすべてのライフサイクル管理はクライアントが制御する必要があります。*6(Springコンテナのビーンライフサイクルの詳細については、Section 5.6.1, “Lifecycle callbacks”)を参照してください。)
5.5.3 Singleton beans with prototype-bean dependencies
プロトタイプビーンの依存性にシングルトンスコープのビーンを使う場合、その依存性はインスタンス時に解決される(dependencies are resolved at instantiation time)ことに注意してください。それ故に、プロトタイプスコープのビーンをシングルトンスコープにインジェクトする場合、新規のプロトタイプビーンをインスタンス化してからシングルトンビーンに依存性注入を行います。プロトタイプのインスタンスは一つだけでそれがシングルトンスコープのビーンに注入したままになります。
とはいえ、実行時には毎回プロトタイプスコープビーンの新規インスタンスを取得するようにシングルトンスコープビーンを設定したいかもしれません。プロトタイプスコープビーンをシングルトンビーンには依存性注入出来ませんが、その理由は、Springコンテナがシングルトンビーンをインスタンス化して解決して依存性を注入するとき、注入がただ一度のみだからです。一度でなく実行時にプロトタイプビーンの新規インスタンスが必要な場合、Section 5.4.6, “Method injection”を参照してください。
5.5.4 Request, session, and global session scopes
request
, session
, global session
スコープは、web-aware Spring ApplicationContext
実装(XmlWebApplicationContext
など)を使う場合のみ、利用可能です。ClassPathXmlApplicationContext
など素のSpring IoCコンテナでこのスコープを使おうとすると、不明なビーンスコープを示すIllegalStateException
をスローします。
Initial web configuration
request
, session
, global session
レベル(web-scoped beans)のビーンスコープを使うには、初期設定が必要です(この初期設定は標準スコープであるsingletonとprototypeには不要)。
この初期設定はServlet環境に依存します。
Spring Web MVC内、実質上は、SpringのDispatcherServlet
やDispatcherPortlet
が処理するリクエスト内のスコープ付きビーンにアクセスする場合、特に設定は必要ありません。DispatcherServlet
やDispatcherPortlet
は関連状態をすべて公開しています。
SpringのDispatcherServletの外側で処理されるリクエスト(たとえばJSFやStruts)を用いるServlet 2.5ウェブコンテナの場合、org.springframework.web.context.request.RequestContextListener
ServletRequestListener
を登録する必要があります。Servlet 3.0+では、WebApplicationInitializer
経由でプログラム的に設定できます。また、古いコンテナでは、web.xml
に以下の宣言を追加します。
<web-app> ... <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> ... </web-app>
また、リスナーセットアップに問題が発生する場合、RequestContextFilter
を試して下さい。フィルターマッピングは環境固有のアプリケーション設定に応じて適切に書き換えてください。
<web-app> ... <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app>
DispatcherServlet
, RequestContextListener
, RequestContextFilter
はすべて同じことをし、リクエストを処理するThread
にHTTPリクエストオブジェクトをバインドします。リクエストおよびセッションスコープビーンを、呼び出しチェーンの大本として使用可能にします*8。
Request scope
以下のビーン定義を解説します。
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
SpringコンテナはHTTPリクエストごとに毎回loginAction
ビーン定義を用いてLoginAction
ビーンの新規インスタンスを生成します。つまり、loginAction
ビーンはHTTPリクエストレベルのスコープです。要求して生成されたインスタンスの内部状態を変更可能で、同一のloginAction
ビーン定義で生成した他インスタンスからはその状態変更は不可視です。内部状態は個々のリクエストごとに独立しています。リクエスト処理の完了後に、リクエストスコープのビーンは破棄されます。
Session scope
以下のビーン定義を解説します。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
Springコンテナは単一のHTTPSession
ライフサイクル用のuserPreferences
ビーン定義を用いてUserPreferences
ビーンの新規インスタンスを生成します。言い換えると、userPreferences
ビーンは実質的にHTTPSession
レベルのスコープです。request-scoped
ビーン同様に、インスタンスの内部状態を変更可能で、同一のuserPreferences
ビーン定義で生成したインスタンスを使用するHTTPSession
インスタンスからはその内部状態の変更は不可視です。内部状態は個々のHTTPSession
ごとに独立しています。HTTPSession
が最終的に破棄されるとき、HTTPSession
スコープのビーンも同様に破棄されます。
Global session scope
以下のビーン定義を解説します。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>
global session
スコープは標準的なHTTPSession
スコープ(上述)と似ており、ポートレットベースwebアプリケーションのコンテキストでだけ使用します。ポートレット仕様は単一のポートレットwebアプリケーションで構成される全ポートレット間で共有するグローバルSession
の概念を定義しています。global session
スコープのビーン定義はグローバルポートレットSession
のライフタイムスコープになります。
標準的なサーブレットベースのwebアプリケーションを作成していてglobal session
スコープのビーン定義をする場合、標準的なHTTPSession
が使用され、特にエラーは発生しません。
Application scope
以下のビーン定義を解説します。
<bean id="appPreferences" class="com.foo.AppPreferences" scope="application"/>
Springコンテナはwebアプリケーション全体で一つのappPreferences
ビーン定義を用いてAppPreferences
ビーンの新規インスタンスを生成します。つまり、appPreferences
ビーンはServletContext
レベルのスコープとなり、通常はServletContext
属性として保存されます。Springのシングルトンビーンと酷似していますが二つの点で異なります。一つは、ServletContext
ごとのシングルトンであってSpringのApplicationContextごとではありません(複数のwebアプリケーションに複数のApplicationContextが存在しても良い*9)。もう一つは、公開されるのでServletContext
属性として参照可能です。
Scoped beans as dependencies
Spring IoCコンテナはオブジェクト(ビーン)のインスタンス化の管理だけでなく、協調オブジェクト(ないし依存性)のワイヤリングも行います。HTTPリクエストスコープのビーンを別のビーンに注入したい場合、スコープビーンにAOPプロキシをインジェクトする必要があります。つまり、スコープオブジェクトのpublicインタフェースを公開するプロキシオブジェクトをインジェクトする必要があり、このプロキシは関連スコープ(例:HTTPリクエストなど)のターゲットオブジェクトの実体を参照し、委譲メソッドが実オブジェクトを呼び出します。
singletons
もしくはprototypes
スコープのビーンと組み合わせるのに<aop:scoped-proxy/>
を使う必要はありません。*10
下記例の設定は一行だけですが*11、"どのように設定するか"(と同様にその背後にある"なぜそうしなければならないか"を理解することも重要です。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- プロキシとして公開するHTTPセッションスコープビーン --> <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <!-- instructs the container to proxy the surrounding bean --> <aop:scoped-proxy/> </bean> <!-- 上記のプロキシビーンをインジェクトするシングルトンスコープビーン --> <bean id="userService" class="com.foo.SimpleUserService"> <!-- a reference to the proxied userPreferences bean --> <property name="userPreferences" ref="userPreferences"/> </bean> </beans>
プロキシを作成するには、スコープビーン定義に子要素<aop:scoped-proxy/>
を追加します。the section called “Choosing the type of proxy to create”とChapter 34, XML Schema-based configurationを参照してください。なぜrequest
, session
, globalSession
とカスタムスコープのビーン定義に<aop:scoped-proxy/>
要素が必要なのでしょうか? 以下のシングルトンビーン定義を説明し、前述のスコープで定義する必要のあったものとの比較を行います。(以下のuserPreferences
ビーン定義は現段階では不完全です。)
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
上記の例では、シングルトンビーンuserManager
にHTTPSession
スコープビーンuserPreferences
の参照をインジェクトします。ここでの主なポイントはuserManager
がシングルトンだということです。このビーンはコンテナごとにただ一度だけ(exactly once)インスタンス化され、その依存性(この例ではuserPreferences
ビーンのみ)もまた一度だけインジェクトされます。つまり、userManager
ビーンは常に同一の最初にインジェクトされたuserPreferences
オブジェクトだけ呼び出すことになります。
この振る舞いは短命のスコープをより長命のスコープビーンにインジェクトする場合、たとえばHTTPSession
スコープの協調ビーンをシングルトンビーンの依存性としてインジェクトするなど、に期待する動作ではありません。正しくは、一つのuserManager
オブジェクトを必要とし、HTTPSession
ライフタイム用には、HTTPSession
に固有のuserPreferences
を必要とします。それ故に、コンテナはUserPreferences
クラス(概念上はUserPreferences
を継承する(is a)オブジェクト)と完全に同一のpublicインタフェースを公開するオブジェクトを生成します。このオブジェクトはスコープのメカニズムから実UserPreferences
オブジェクトを取得します。コンテナはこのプロキシオブジェクトをuserManager
ビーンにインジェクトし、userManager
ではUserPreferences
参照がプロキシかどうかは意識しません。この例では、UserManager
インスタンスが依存性注入されたUserPreferences
オブジェクトのメソッドを呼び出すときに、プロキシ上のメソッドを実際に実行します。それから、プロキシはHTTPSession
からUserPreferences
の実オブジェクトを取得し、UserPreferences
実オブジェクトのメソッド実行を委譲します。
よって、request-
, session-
, globalSession-scoped
ビーンを協調オブジェクトにインジェクトする場合には、正しくは以下のようにする必要があります。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <aop:scoped-proxy/> </bean> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
Choosing the type of proxy to create
デフォルトでは、Springコンテナが<aop:scoped-proxy/>
要素を付与されたビーンのプロキシを生成する場合、CGLIBベースのクラスプロキシを生成します(a CGLIB-based class proxy is created)。
CGLIBプロキシはpublicメソッド呼び出しのみインターセプトします! プロキシでは非publicメソッドを呼び出さないでください。非publicメソッドは実際のスコープオブジェクトへの委譲を行いません。
代わりに、スコープビーン用に標準JDKインタフェースベースプロキシを生成するようSpringコンテナを設定可能です。この設定は<aop:scoped-proxy/>
要素のproxy-target-class
をfalse
に指定します。なお、JDKインタフェースベースプロキシを使う際にはアプリケーションのクラスパスにプロキシを有効化するための追加ライブラリは必要ありません。ただし、スコープビーンのクラスは少なくとも一つインタフェースを実装する必要があり、そのスコープビーンを注入するすべての協調ビーンはそのインタフェースのうち一つを通してビーンを参照する必要があります。
<!-- DefaultUserPreferencesはUserPreferencesインタフェースを実装する --> <bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session"> <aop:scoped-proxy proxy-target-class="false"/> </bean> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
クラスベースもしくはインタフェースベースプロキシの選択に関する詳細についてはSection 9.6, “Proxying mechanisms”を参照してください。
5.5.5 Custom scopes
ビーンスコープのメカニズムは拡張可能です。自前のスコープ定義や既存スコープの再定義が可能ですが、後者は邪悪な行い*12と思われます。また、組み込みのsingleton
とprototype
スコープはオーバーライド不可です。
Creating a custom scope
カスタムスコープをSpringコンテナに導入するには、このセクションで解説するorg.springframework.beans.factory.config.Scope
インタフェースを実装します。自前のスコープを実装する方法を知るには、実装の必要があるメソッドの詳細を解説しているScope
のjavadocとSpring Framework自身のScope
の実装を参照してください。
Scope
インタフェースには4つのメソッドがあり、スコープからのオブジェクト取得・削除・allow them to be destroyed*13、です。
以下のメソッドは対象スコープからのオブジェクトを返します。例えばセッションスコープ実装では、セッションスコープビーンを返します(もし存在しなければ、メソッドはビーンの新規インスタンスを、将来の参照時のためにセッションにバインドした上で、返します)。
Object get(String name, ObjectFactory objectFactory)
以下のメソッドは対象スコープからオブジェクトを削除します。例えばセッションスコープ実装では、対象セッションからセッションスコープビーンを削除します。オブジェクトを戻り値として返すべきですが、引数で指定した名前のビーンが存在しないオブジェクトについてはnullを返しても構いません。
Object remove(String name)
以下のメソッドは、破棄時あるいはスコープの指定オブジェクト破棄時に、スコープが実行すべきコールバックを登録します。破棄時コールバックの詳細な情報についてはSpringスコープ実装かjavadocを参照してください。
void registerDestructionCallback(String name, Runnable destructionCallback)
以下のメソッドは対象スコープのconversation identifierを取得します。この識別子はスコープごとに異なります。セッションスコープ実装では、この識別子はセッション識別子になります*14。
String getConversationId()
Using a custom scope
カスタムScope
実装を作成&テストしたら、Springコンテナがその新規スコープを認識するように設定します。以下のメソッドがSpringコンテナに新規Scope
を登録するために中核となるメソッドです。
void registerScope(String scopeName, Scope scope);
このメソッドはConfigurableBeanFactory
インタフェースに宣言されており、大抵のApplicationContext
実装がBeanFactoryプロパティ経由でSpringに乗っけているのでそこから利用可能です。
registerScope(..)
メソッドの最初の引数はスコープと関連付ける一意な名前で、Springコンテナの例でいうとsingleton
やprototype
です。二番目の引数は登録および使用したいカスタムScope
実装の実際のインスタンスです。
いま、カスタムScope
実装を作成して以下のように登録したとします。
下記の例はSpringに含まれているSimpleThreadScope
を使用していますが、デフォルトでは未登録です。やり方そのものは自前のScope
実装であっても同一です。
Scope threadScope = new SimpleThreadScope(); beanFactory.registerScope("thread", threadScope);
カスタムScope
のスコープルールに従いビーン定義を作成します。
<bean id="..." class="..." scope="thread">
カスタムScope
実装に関しては、スコープの登録方法はコードを書く以外にも方法があります。Scope
登録を宣言的に行うにはCustomScopeConfigurer
クラスを使います。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread"> <bean class="org.springframework.context.support.SimpleThreadScope"/> </entry> </map> </property> </bean> <bean id="bar" class="x.y.Bar" scope="thread"> <property name="name" value="Rick"/> <aop:scoped-proxy/> </bean> <bean id="foo" class="x.y.Foo"> <property name="bar" ref="bar"/> </bean> </beans>
FactoryBean
実装に<aop:scoped-proxy/>
を設定すると、getObject()
が返すオブジェクトではなく、スコープ下のファクトリービーン自身になります。*15
5.6 Customizing the nature of a bean
5.6.1 Lifecycle callbacks
ビーンライフサイクルのコンテナ管理に絡む処理を加えるには、SpringのSpring InitializingBean
とDisposableBean
インタフェースを実装します。コンテナは前者用にafterPropertiesSet()
、後者用にdestroy()
を呼び出し、これらを使用してビーンの初期化と破棄時に何らかのアクションを実行可能です。
JSR-250 @PostConstruct
と@PreDestroy
アノテーションは、通常は、モダンなSpringアプリケーションでライフサイクルコールバックを受けるためのベストプラクティスだと思われます。これらのアノテーションを使うということは、Spring固有のインタフェースにビーンを依存させない、という意味合いになります。詳細はSection 5.9.7, “@PostConstruct and @PreDestroy”を参照してください。
もしJSR-250アノテーションを使いたくないなら、オブジェクト定義メタデータのinit-methodとdestroy-methodの使用を考慮に入れて、結合を取り除く努力をした方が良いでしょう*16。
内部的には、Spring Frameworkは、適切なメソッドの参照と呼び出しが可能なコールバックインタフェースを処理するのに、BeanPostProcessor
実装を使用します。もしSpringがデフォルトで提供しないその他のライフサイクルの振る舞いやカスタム機能が必要な場合は自前でBeanPostProcessor
を実装します。詳細については、Section 5.8, “Container Extension Points”を参照してください。
初期化と破棄時のコールバックに加えて、Spring管理オブジェクトはLifecycle
インタフェースも実装可能で、そうしたオブジェクトはコンテナのライフサイクルが基点となるスタートアップとシャットダウン処理への関連付けが可能になります。
ライフサイクルコールバックインタフェースはこのセクションで説明します。
Initialization callbacks
org.springframework.beans.factory.InitializingBean
インタフェースは、コンテナがビーンのすべての必要なプロパティを設定し終えた後に、ビーンが初期化処理を行うために使用します。InitializingBean
には一つのメソッドが定義してあります。
void afterPropertiesSet() throws Exception;
しかし、Springコードに対する不必要な結合を生んでしまうため、InitializingBean
インタフェースは使用しないことを推奨します。代わりに、@PostConstruct
アノテーションを使うか、POJO初期化メソッドを指定してください。XML設定メタデータでは、init-method
属性にvoid戻り値型の引数無しシグネチャのメソッド名を指定します。Java設定で行うには@Bean
のinitMethod
属性を使用し、詳細はthe section called “Receiving lifecycle callbacks”を参照してください。例は以下の通りです。
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean { public void init() { // do some initialization work } }
下記は上記と同じ意味です……
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean { public void afterPropertiesSet() { // do some initialization work } }
……が、Springコードに結合しないようにして下さい。
Destruction callbacks
org.springframework.beans.factory.DisposableBean
インタフェースを実装することで、コンテナがビーン破棄する時にコールバックを実行可能になります。DisposableBean
には一つのメソッドが定義してあります。
void destroy() throws Exception;
しかし、Springコードに対する不必要な結合を生んでしまうため、DisposableBean
インタフェースは使用しないことを推奨します。代わりに、@PreDestroy
アノテーションを使うか、ビーン定義がサポートするジェネリックメソッドを指定してください。XML設定メタデータでは、<bean/>
のdestroy-method
属性を使います。Java設定で行うには@Bean
のdestroyMethod
属性を使用し、詳細はthe section called “Receiving lifecycle callbacks”を参照してください。例は以下の通りです。
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) } }
下記は上記と同じ意味です……
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean { public void destroy() { // do some destruction work (like releasing pooled connections) } }
……が、Springコードに結合しないようにして下さい。
<bean>
要素のdestroy-method
属性には特殊な(inferred)
値を指定可能で、この値は指定ビーンクラスのpublic close
あるいはshutdown
メソッドを自動検出するようSpringに指示するものです。この特殊な(inferred)
値は<beans>
要素のdefault-destroy-method
属性で設定可能で、beans全体にこの振る舞いを適用するために使用します(詳細はthe section called “Default initialization and destroy methods”を参照してください)。注意点として、Java設定ではこちらがデフォルトの振る舞いです
Default initialization and destroy methods
Spring固有のInitializingBean
とDisposableBean
コールバックインターフェースを使わない、初期化および破棄メソッドコールバックを作るには、通常、init()
, initialize()
, dispose()
などの名前を持つメソッドを作成します。理想的には、すべての開発者が同一のメソッド名を使用して一貫性を保つため、プロジェクト全体でライフサイクルコールバックメソッド名は標準化しておきます。
Springコンテナの設定により、すべてのビーンの初期化および破棄コールバックメソッド名を検索(look
for)するように出来ます。この意味するところは、アプリケーション開発者が、ビーン定義にinit-method="init"
を設定しなくとも、初期化コールバックにinit()
を使用するような、コーディングが可能です。Spring IoCコンテナはビーン生成時に初期化メソッドを呼び出します(なお、前述した標準ライフサイクルコールバック契約に従います)。この機能は初期化と破棄メソッドコールバックに一貫性のある命名規則を強制します。
いま、初期化コールバックメソッドがinit()
で破棄コールバックメソッドがdestroy()
と仮定します。その場合、以下のサンプルと似たような感じになるでしょう。
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."); } } }
<beans default-init-method="init"> <bean id="blogService" class="com.foo.DefaultBlogService"> <property name="blogDao" ref="blogDao" /> </bean> </beans>
トップレベル<beans/>
要素のdefault-init-method
属性の存在により、Spring IoCコンテナはビーンのinit
を初期化メソッドコールバックとして認識します。ビーン生成およびアセンブル時に、もしビーンクラスがそうしたメソッドを持っていれば、適切なタイミングで呼び出されます。
同じく、破棄メソッドコールバックの設定は(XMLでは)トップレベル<beans/>
要素のdefault-destroy-method
属性を使用します。
既存のビーンクラスが規約と衝突する名前で既にコールバックメソッドを持っている箇所では、<bean/>
のinit-method
とdestroy-method
属性を使用してメソッド名を(XMLで)指定することでデフォルトをオーバーライドできます。
Springコンテナは、あるビーンのすべての依存性を供給した直後に、設定した初期化コールバックを呼び出すことを保証します。
初期化コールバックはロウビーン参照(raw bean reference)*17で実行しますが、その意味は、AOPインターセプターなどその他諸々はまだビーンに適用していない、ということです。ターゲットビーンをまず始めに完全に生成してから、インターセプターチェーンのAOPプロキシ(など)を適用します。ターゲットビーンとプロキシを別々に定義している場合、プロキシをバイパスして、ロウターゲットビーン(raw target bean)との相互作用が可能です。それ故に、初期化メソッドにインターセプターを適用するのは矛盾しており、なぜなら、プロキシ/インターセプターにターゲットビーンのライフサイクルを結びつけると、raw target beanに直接相互作用する場合におかしな動作となります(leave strange semantics)。
Combining lifecycle mechanisms
Spring 2.5以降では、ビーンライフサイクルの振る舞いを制御する三つのオプションが使えます。InitializingBean
とDisposableBean
のコールバックインタフェース、カスタムinit()
とdestroy()
、@PostConstruct
と@PreDestroy
アノテーション。ビーンを制御するのにこれらのメカニズムを組み合わせて使います。
もし複数のライフサイクルメカニズムをビーンに設定したり、異なるメソッド名でそれぞれのメカニズムを設定した場合、以下に示す順序でそれぞれに設定したメソッドを実行します。ただし、同一のメソッド名を設定した場合、たとえば、初期化メソッドにinit()
を、更に、各ライフサイクルメカニズムの一つ以上に同一のメソッドを指定した場合、前述のセクションで説明したように、そのメソッドは一度だけ実行します。
異なる初期化メソッドを、同一ビーンに複数設定した場合、以下のように呼び出します。
@PostConstruct
アノテーションを付与したメソッド。InitializingBean
コールバックインタフェースで定義するafterPropertiesSet()
- カスタム設定
init()
メソッド
破棄メソッドも同じ順序で呼び出します。
Startup and shutdown callbacks
Lifecycle
インタフェースはライフサイクル要求を持つオブジェクト用の基本的なメソッドを定義しています(たとえば、バックグラウンドプロセスを開始&停止するなど)。
public interface Lifecycle { void start(); void stop(); boolean isRunning(); }
Springマネージドオブジェクトはいずれもこのインターフェースを実装可能です。すなわち、ApplicationContext
が開始と停止するとき、コンテキスト内に定義されているすべてのLifecycle
実装の呼び出しをカスケードします。LifecycleProcessor
にデリゲートすることでカスケードを行います。
public interface LifecycleProcessor extends Lifecycle { void onRefresh(); void onClose(); }
LifecycleProcessor
はLifecycle
インタフェースの拡張な点に注意してください。コンテキストのリフレッシュ&クローズに対応する二つのメソッドを追加しています。
startupとshutdownの呼び出し順序が重要な場合があります。ある二つのオブジェクト間に"依存"("depends-on")関係が存在する場合、依存する側は依存性の後に開始し、依存性の前に停止します。しかし、時には直接的な依存性が不明確なことがあります。ある特定の型のオブジェクトが、別の型のオブジェクトよりも先に開始しなければならないと、開発者だけが知っている場合があるかもしれません。そうした場合、SmartLifecycle
インタフェースは別のオプションを定義しており、スーパーインタフェースPhased
にgetPhase()
メソッドがあります。
public interface Phased { int getPhase(); }
public interface SmartLifecycle extends Lifecycle, Phased { boolean isAutoStartup(); void stop(Runnable callback); }
開始時に、最も低いフェーズのオブジェクトが最初に開始し、終了時には逆順になります。それゆえに、SmartLifecycle
を実装するオブジェクトでgetPhase()
メソッドがInteger.MIN_VALUE
を返すものは最初に開始して最後に停止します。一方、フェーズ値Integer.MAX_VALUE
はオブジェクトが最後に開始して最初に停止すべきなことを指示します(他で実行しているプロセスに依存する可能性があるので)*18。フェーズ値を考慮する場合、SmartLifecycle
を実装しない"普通"("normal")のLifecycle
オブジェクトのデフォルトフェーズは0なことは知っておく必要があります。それゆえに、マイナスのフェーズ値はそのオブジェクトが通常コンポーネントの前に開始(停止はその逆)すべきと指示することになり、プラスのフェーズ値はその逆です。
上述の通り、SmartLifecycle
の停止メソッドはコールバックを受け取ります。いずれの実装においても、その実装におけるシャットダウン処理完了後にコールバックのrun()
メソッドを必ず実行する必要があります。必要箇所では非同期シャットダウンが可能で、LifecycleProcessor
のデフォルト実装DefaultLifecycleProcessor
はコールバックを呼び出す各フェーズ内のオブジェクトグループ用のタイムアウト値まで待機します。各フェーズごとのデフォルトタイムアウト値は30秒です。コンテキスト内に"lifecycleProcessor"ネームドビーンを定義することで、デフォルトライフサイクルプロセッサーインスタンスをオーバーライドできます。タイムアウトのみ修正したい場合、以下の定義で十分です。
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor"> <!-- timeout value in milliseconds --> <property name="timeoutPerShutdownPhase" value="10000"/> </bean>
上記の通り、LifecycleProcessor
インタフェースはコンテキスト同様にリフレッシュとクローズ用のコールバックメソッドを定義します。後者は、stop()
が明示的に呼ばれたかのようにシャットダウン処理をただ単に進めるだけで、コンテキストクローズ時に発生します。もう片方のrefreshコールバックはSmartLifecycle
ビーンのもう一つの機能を有効にします。(全オブジェクトのインスタンス化および初期化後の)コンテキストリフレッシュ時に、そのコールバックを呼び出し、その時点でデフォルトライフサイクルプロセッサーは各SmartLifecycle
オブジェクトのisAutoStartup()
メソッドが返すboolean値をチェックします。もし"true"であればオブジェクトはその時点で開始しており、自身のstart()
メソッドやコンテキストの明示的実行で待機していません(コンテキストリフレッシュとは異なり、コンテキストスタートは標準コンテキスト実装では自動的に発生しません)。"depends-on"関係と同様に"phase"値も上述同様な方法でスタートアップ順序を決定します。
Shutting down the Spring IoC container gracefully in non-web applications
このセクションは非webアプリケーションにのみ適用されます。SpringのwebベースApplicationContext
実装は、関連webアプリケーションシャットダウン時に、Spring IoCコンテナをgracefully*19にシャットダウンするためのインプレースなコードが含まれています。
非webアプリケーション環境でSpring IoCコンテナを使用する場合、例えばデスクトップ環境のリッチクライアントなどでは、JVMにシャットダウンフックを登録します。これによりgracefulなシャットダウンを保証し、シングルトンビーンに関連付けられた破棄メソッドを実行し、それによって全リソースを解放します。当然のことながら、破棄コールバックを正しく実装して設定していることが前提条件です。
シャットダウンフックを登録するには、AbstractApplicationContext
クラスに宣言されているregisterShutdownHook()
メソッドを呼び出します。
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public final class Boot { public static void main(final String[] args) throws Exception { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext( new String []{"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... } }
5.6.2 ApplicationContextAware and BeanNameAware
ApplicationContext
がorg.springframework.context.ApplicationContextAware
インタフェースを実装するオブジェクトインスタンスを生成する場合、そのインスタンスにはApplicationContext
の参照が渡されます。
public interface ApplicationContextAware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }
こうしたビーンは、そのビーンを生成したApplicationContext
インタフェースをプログラム的に操作可能で、また、ApplicationContext
インタフェースが追加機能を公開するConfigurableApplicationContext
などの既知のサブクラスであれば参照をキャストします。使い方の一例としては他ビーンのプログラム的な検索などです。時としてこの機能は役立ちますが、通常は避けるべきです。その理由は、Springコードに依存し、また、協調オブジェクトがプロパティとしてビーンに与えられる箇所では制御の反転スタイルに反しているためです。ApplicationContext
のその他メソッドとしては、ファイルリソースへのアクセス・アプリケーションイベントのパブリッシュ・MessageSource
へのアクセス、を提供します。そうした追加機能についてはSection 5.15, “Additional Capabilities of the ApplicationContext”で解説します。
Spring 2.5以降では、オートワイヤがApplicationContext
の参照を取得するもう一つの手段になりました。伝統的な("traditional")constructor
とbyType
オートワイヤモード(Section 5.4.5, “Autowiring collaborators”で解説したもの)ではセッターメソッドないしコンストラクタ引数のApplicationContext
型で依存性を入れられます。より柔軟なやり方としては、複数パラメーターメソッドとオートワイヤフィールド機能など、新しいアノテーションベースのオートワイヤ機能を使います。対象となるフィールド・コンストラクタ・メソッドが@Autowired
アノテーションを持つ場合、ApplicationContext
型を期待するフィールド・コンストラクタ引数・メソッドパラメータへ、ApplicationContext
がオートワイヤされます。詳細についてはSection 5.9.2, “@Autowired”を参照してください。
ApplicationContext
はorg.springframework.beans.factory.BeanNameAware
インタフェースを実装するクラスを生成し、このクラス関連オブジェクト定義で定義された名前で参照を保持します。
public interface BeanNameAware { void setBeanName(string name) throws BeansException; }
このコールバックが実行されるのは、通常のビーンプロパティ投入(population)後ですが、カスタムinit-methodもしくはafterPropertiesSetより後のInitializingBean
等の初期化コールバックより前、になります*20。
5.6.3 Other Aware interfaces
上述のApplicationContextAware
とBeanNameAware
に加え、Springはビーンが特定のinfrastructure依存性をコンテナに要求出来るような各種のAware
インタフェースを提供します。最も重要なAware
インタフェースは以下にまとめた通りで、命名規則としては、名称が依存性の種類を示しています。
Table 5.4. Aware interfaces
Name | Injected Dependency | Explained in… |
---|---|---|
ApplicationContextAware |
ApplicationContext の宣言 |
Section 5.6.2, “ApplicationContextAware and BeanNameAware” |
ApplicationEventPublisherAware |
エンクロージングApplicationContext のイベントパブリッシャー |
Section 5.15, “Additional Capabilities of the ApplicationContext” |
BeanClassLoaderAware |
ビーンクラスのロードに使うクラスローダー | Section 5.3.2, “Instantiating beans” |
BeanFactoryAware |
BeanFactory の宣言 |
Section 5.6.2, “ApplicationContextAware and BeanNameAware” |
BeanNameAware |
ビーンの宣言名 | Section 5.6.2, “ApplicationContextAware and BeanNameAware” |
BootstrapContextAware |
コンテナが動作しているリソースアダプターBootstrapContext 。基本的にJCA aware ApplicationContext s でのみ利用可能 |
Chapter 26, JCA CCI |
LoadTimeWeaverAware |
ロード時のクラス定義処理におけるweaver定義 | Section 9.8.4, “Load-time weaving with AspectJ in the Spring Framework” |
MessageSourceAware |
メッセージ解決用に定義されたストラテジ(パラメータ化と国際化サポート含む) | Section 5.15, “Additional Capabilities of the ApplicationContext” |
NotificationPublisherAware |
Spring JMX通知パブリッシャー | Section 25.7, “Notifications” |
PortletConfigAware |
コンテナが動作している現在のPortletConfig 。web-aware Spring ApplicationContext でのみ有効 |
Chapter 20, Portlet MVC Framework |
PortletContextAware |
コンテナが動作している現在のPortletContext 。web-aware Spring ApplicationContext でのみ有効 |
Chapter 20, Portlet MVC Framework |
ResourceLoaderAware |
リソースへの低レベルアクセス用に設定されたローダー | Chapter 6, Resources |
ServletConfigAware |
コンテナが動作している現在のServletConfig 。web-aware Spring ApplicationContext でのみ有効 |
Chapter 17, Web MVC framework |
ServletContextAware |
コンテナが動作している現在のServletContext 。web-aware Spring ApplicationContext でのみ有効 |
Chapter 17, Web MVC framework |
再度の注意になりますが、これらのインタフェースを使うことはSpring APIに依存することになり制御の反転スタイルに反することになります。それゆえに、コンテナへのプログラム的なアクセスを要求するinfrastructureビーンを推奨します。
5.7 Bean definition inheritance
ビーン定義には多くの設定情報を持つことが可能で、それにはコンストラクタ引数・プロパティ値・初期化メソッドなどコンテナ固有情報・staticファクトリーメソッド名などなどがあります。子ビーン定義は親定義から設定データを継承します。子定義は必要に応じて値のオーバーライドや追加が可能です。親・子ビーンを定義を使うことでタイピングの手間を減らせます。実質的には、これはテンプレートになります。
プログラム的にApplicationContext
インタフェースを動かしたい場合、子ビーン定義はChildBeanDefinition
クラスで表現します。とはいえ大抵の場合このレベルで動かかすことは無く、代わりに、ClassPathXmlApplicationContext
などの宣言的な設定ビーン定義を使います。XML設定メタデータを使う場合、parent
属性で子ビーン定義を指定し、この属性値に親ビーンの値を指定します。
<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize"> <property name="name" value="override"/> <!-- the age property value of 1 will be inherited from parent --> </bean>
子ビーン定義は何も指定しなければ親のビーンクラスを使用しますが、オーバーライドすることも出来ます。オーバーライドする場合、子ビーンクラスは親との互換性が必須であり、つまり、親プロパティ値を受け入れられる必要があります。
子ビーン定義は、スコープ・コンストラクタ引数値・プロパティ値・親からオーバーライドしたメソッド(に値を追加可能)、を継承します。子ビーンで指定する、スコープ・初期化メソッド・破棄メソッド・static
ファクトリーメソッド設定は、一致する親の設定をオーバーライドします。
残りの設定、depends on, autowire mode, dependency check, singleton, lazy init、は常に子定義のモノを使います。
前述の例は明示的にabstract
属性を使用して親ビーン定義にabstarctとマークしています。親ビーン定義でクラス指定をしない場合、明示的に親ビーン定義にabstract
をマークする必要があります。
<bean id="inheritedTestBeanWithoutClass" abstract="true"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBeanWithoutClass" init-method="initialize"> <property name="name" value="override"/> <!-- age will inherit the value of 1 from the parent bean definition--> </bean>
親ビーンだけでは不完全でインスタンス化出来ないので、明示的にabstract
とマークしてあります。こうしたabstract
定義は、子定義用の親定義を提供する純粋なテンプレートビーンとしてのみ使用可能です。別のビーンでrefプロパティとして参照しようとしたり、親ビーンIDで明示的なgetBean()
呼び出すなどで、abstract
な親ビーンを使おうとした場合はエラーが返されます。同様に、コンテナ内部のpreInstantiateSingletons()
メソッドはabstractとして定義したビーン定義を無視します。
デフォルトではApplicationContext
はすべてのシングルトンをpre-instantiatesします。ゆえに、
(親)ビーン定義をテンプレートとしてのみ使うよう指定する場合、(少なくともシングルトンビーンにとっては)重要であり、その場合は、abstract属性をtrueに設定しなければなりません。さもないと、アプリケーションコンテキストはabstract
ビーンのpre-instantiateを(試みようと)します。
5.8 Container Extension Points
一般的に、アプリケーション開発者はApplicationContext
実装クラスのサブクラスを必要としません。その代わりに、Spring IoCコンテナは特別なインテグレーションインタフェースを実装したプラグインによって拡張可能です。以降のセクションではそうしたインテグレーションインタフェースについて説明します。
5.8.1 Customizing beans using a BeanPostProcessor
BeanPostProcessor
インタフェースは、自前(かコンテナデフォルトのオーバーライド)のインスタンス化ロジック・依存性解決ロジック・などなど、の実装が可能なコールバックメソッド(callback methods)を提供します。Springコンテナがインスタンス化・設定・ビーン初期化後にカスタムロジックを実装したい場合、一つ以上のBeanPostProcessor
実装をプラグ可能です。複数のBeanPostProcessor
インスタンスを設定可能で、order
プロパティを設定することで複数のBeanPostProcessor
の実行順序を制御できます。BeanPostProcessor
がOrdered
インタフェースを実装する場合のみこのプロパティは設定可能です。そのため、自前のBeanPostProcessor
を作る場合にはOrdered
インタフェースを実装することも考慮に入れてください。より詳しい詳細については、BeanPostProcessor
とOrdered
のjavadocを参照してください。また、BeanPostProcessors
のプログラム的な登録の項も参照してください。
BeanPostProcessor
はビーン(かオブジェクト)インスタンス(instances)上で実行します。ということはつまり、Spring IoCコンテナはビーンインスタンスをインスタンス化してからBeanPostProcessor
を実行します。BeanPostProcessor
のスコープはコンテナ毎(per-container)です。このことはコンテナ階層を使用する場合にみ関係があります。あるコンテナにBeanPostProcessor
を定義したとき、そのコンテナのビーンのみpost-processします。言い換えると、あるコンテナで定義したビーンは、別のコンテナで定義したBeanPostProcessor
ではpost-processされません。たとえ両コンテナが同一階層の一部だったとしても同様です*21。実際のビーン定義を変更(i.e., the blueprint that defines the bean)*22するには、Section 5.8.2, “Customizing configuration metadata with a BeanFactoryPostProcessor”で解説されているBeanFactoryPostProcessor
を使う必要があります。
org.springframework.beans.factory.config.BeanPostProcessor
インタフェースにはコールバックメソッドが二つだけあります。コンテナにpost-processorとしてクラスをを登録すると、コンテナが生成した各ビーンインスタンスごとに、post-processorはコンテナの初期化メソッド(初期化するビーンのafterPropertiesSet()
と任意に宣言したinitメソッド)より前にコールバックを受け取り、同様に、ビーン初期化コールバックより後にコールバックを受け取ります。post-processorはビーンインスタンスに対して任意の処理が可能で、コールバックを無視しても構いません。ビーンのpost-processorは一般的にはコールバックインターフェースのチェックやプロキシによるビーンのラップを行います。Spring AOPインフラクラスにはプロキシラップロジックを提供するのにbean post-processorsとして実装しているものがあります。
ApplicationContext
はBeanPostProcessor
インタフェースを実装する設定メタデータで定義したビーンを自動検出(automatically detects)します。ApplicationContext
は検出したビーンをpost-processorsとして登録し、後々のビーン生成時に呼び出します。Bean post-processorsは他のビーン同様にコンテナへデプロイ可能です。
注意点として、設定クラスで@Bean
ファクトリーメソッドを使用してBeanPostProcessor
を宣言する場合、ファクトリーメソッドの戻り値型は自身の実装クラスか少なくともorg.springframework.beans.factory.config.BeanPostProcessor
インタフェースにして、そのビーンのpost-processor natureを明確に指定してください*23。そうしないと、ApplicationContext
は生成前にby typeによる自動検出が出来ません。BeanPostProcessor
はコンテキストにおいて他ビーンの初期化に適用される前にインスタンス化する必要があるので、この早期型検出(early type detection)は重要です。
Programmatically registering BeanPostProcessors
BeanPostProcessor
登録の推奨方法はApplicationContext
の自動検出(上述もの)経由ですが、addBeanPostProcessor
メソッドを使用してConfigurableBeanFactory
に対しプログラム的にに登録することも可能です。これは登録前に状態を評価するロジックの必要があったり、階層上のコンテキストを横断するbean post processorsをコピーする場合に有用です。注意点として、プログラム的に追加したBeanPostProcessors
はOrderedインタフェースを考慮しません(do not respect the Ordered interface)。この場合、登録順序(order of registration)が実行順序を決定します。また、プログラム的に登録したBeanPostProcessors
は、自動検出で登録されたものよりも常に前に処理されます。明示的な実行順序があったとしても同じです。
BeanPostProcessors and AOP auto-proxying
BeanPostProcessor
インタフェースを実装するクラスは特別(special)でありコンテナは異なる扱い方をします。すべてのBeanPostProcessors
とこれを直接参照するビーン(and beans that they reference directly)は、ApplicationContext
の特殊なスタートアップフェーズの一部として、スタートアップ時にインスタンス化します。次に、すべてのBeanPostProcessors
をソート形式で登録してコンテナ内のビーンに適用します。AOP auto-proxyingは自身をBeanPostProcessor
として実装しているので、BeanPostProcessors
もこれを直接参照するビーンもauto-proxyingの対象にならず、よって、アスペクトはウィーブされません。ビーンによって次のinfoログメッセージを見ることになるかもしれません。"Bean foo is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying)"(ビーンfooはすべてのBeanPostProcessorインタフェースにおいて処理する事が出来ません(例えばauto-proxyingはBeanPostProcessorによって処理出来ません))
注意点として、オートワイヤもしくは@Resource
(オートワイヤにフォールバックする可能性有)を使用してビーンをBeanPostProcessor
へワイヤする場合、Springは型にマッチする依存性候補の探索時に予期せぬビーン(unexpected beans)にアクセスすることになるので、そのようなBeanPostProcessor
はauto-proxyingもしくは他のbean post-processingには使えないことになります。For example, if you have a dependency annotated with @Resource where the field/setter name does not directly correspond to the declared name of a bean and no name attribute is used, then Spring will access other beans for matching them by type.*24
次にApplicationContext
にBeanPostProcessors
の使用・登録・作成方法の例を示します。
Example: Hello World, BeanPostProcessor-style
最初に基本的な使用方法を示します。この例はBeanPostProcessor
を実装してコンテナがビーンを生成したときにtoString()
メソッドを呼び出してコンソールにその文字列を表示します。
BeanPostProcessor
実装クラスの定義を以下に示します。
package scripting; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.BeansException; public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor { // 単に初期化したビーンを返すだけ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; // 潜在的には任意のオブジェクト参照を返すことも出来なくはない } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("Bean '" + beanName + "' created : " + bean.toString()); return bean; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <lang:groovy id="messenger" script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy"> <lang:property name="message" value="Fiona Apple Is Just So Dreamy."/> </lang:groovy> <!-- 上記のビーン(messenger)がインスタンス化したとき、 このBeanPostProcessor実装がコンソールに結果を出力する。 --> <bean class="scripting.InstantiationTracingBeanPostProcessor"/> </beans>
InstantiationTracingBeanPostProcessor
がシンプルに定義していることに注意してください。名前が無いですが、ビーンなので他のビーンのように依存性注入が可能です(また、上の設定例ではGroovyスクリプトによるビーン定義も行っています。Spring動的言語サポートの詳細についてはChapter 29, Dynamic language supportを参照してください)。
以下は前述のコードと設定をJavaアプリケーションとして実行する例です。
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.scripting.Messenger; public final class Boot { public static void main(final String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml"); Messenger messenger = (Messenger) ctx.getBean("messenger"); System.out.println(messenger); } }
上記のアプリケーションは以下のような結果となります。
Bean messenger created : org.springframework.scripting.groovy.GroovyMessenger@272961 org.springframework.scripting.groovy.GroovyMessenger@272961
Example: The RequiredAnnotationBeanPostProcessor
BeanPostProcessor
を実装してコールバックインターフェースもしくはアノテーションと組み合わせて使うことはSpring IoCコンテナのよくある拡張方法です。その一例はSpringのRequiredAnnotationBeanPostProcessor
で、このBeanPostProcessor
実装は、アノテーションで(任意箇所に)マークしたビーンのJavaBeanプロパティが実際に値を依存性注入(可能なように設定)することを保証するSpringディストリビューションに搭載されています*25。
5.8.2 Customizing configuration metadata with a BeanFactoryPostProcessor
次に見る拡張ポイントはorg.springframework.beans.factory.config.BeanFactoryPostProcessor
です。このインタフェースのセマンティクスはBeanPostProcessor
のそれと似ており、一つの主要な違いは、BeanFactoryPostProcessor
はビーン設定メタデータ(bean configuration metadata)を操作します。これは、Spring IoCコンテナがBeanFactoryPostProcessor
で設定メタデータを参照するのを許可し、コンテナがBeanFactoryPostProcessors
以外のビーンをインスタンス化するよりも前に設定を変更できます。
複数のBeanFactoryPostProcessors
を設定可能で、order
プロパティを設定することでBeanFactoryPostProcessors
の実行順序を制御できます。ただし、BeanFactoryPostProcessor
がOrdered
インタフェースを実装する場合に限りorder
プロパティは設定可能です。自前のBeanFactoryPostProcessor
を作成する場合、Ordered
インタフェースの実装も考慮に入れて下さい。BeanFactoryPostProcessor
とOrdered
インタフェースの詳細についてはjavadocを参照してください。
実際のビーンインスタンス(設定メタデータを基に生成したオブジェクトのこと)を変更したい場合、BeanPostProcessor
(Section 5.8.1, “Customizing beans using a BeanPostProcessor”で解説済み)を使う必要があります。BeanFactoryPostProcessor
内でビーンインスタンスを扱うのは技術的には可能(例えばBeanFactory.getBean()
を使う)ですが、これは早すぎるビーンインスタンス化を発生させ、標準コンテナライフサイクルに違反します。このことはbean post processingのバイパスなど危険な副作用の原因となる可能性があります。
また、BeanFactoryPostProcessors
のスコープはコンテナ毎(per-container)で、これはコンテナ階層を使用する場合のにみ関係があります。あるコンテナにBeanFactoryPostProcessor
を定義する場合、そのコンテナのビーン定義にのみ適用されます。あるコンテナのビーン定義は別コンテナのBeanFactoryPostProcessors
のpost-process対象にならず、二つのコンテナが同一階層の一部だとしても変わりません。
コンテナを定義する設定メタデータの変更するためのbean factory post-processorは、ApplicationContext
内に宣言すると自動的に実行します。Springには、PropertyOverrideConfigurer
やPropertyPlaceholderConfigurer
などの、定義済みbean factory post-processorsがいくつか含まれています。BeanFactoryPostProcessor
のカスタム実装では、たとえば、カスタムプロパティエディターを登録して使用したりすることが出来ます。
ApplicationContext
はBeanFactoryPostProcessor
インタフェースを実装するビーンを自動検出します*26。適時、bean factory post-processorsとしてビーンを使用します。post-processor beansは他のビーン同様にデプロイ可能です。
BeanPostProcessors
同様に、一般的には遅延初期化でBeanFactoryPostProcessors
を設定したいとは思わないでしょう。Bean(Factory)PostProcessor
を参照するビーンが無い場合、そのpost-processorはインスタンス化しません。よって、遅延初期化の設定は無視され、Bean(Factory)PostProcessor
はイーガー(eagerly)にインスタンス化します。もし<beans />
要素の宣言のdefault-lazy-init
属性にtrue
をしたとしても変わりません。
Example: the Class name substitution PropertyPlaceholderConfigurer
PropertyPlaceholderConfigurer
によって標準JavaProperties
フォーマットの別ファイルのビーン定義にプロパティ値を外部化できます。データベースURLとパスワードなど環境固有プロパティを変更してアプリケーションをデプロイするとき、コンテナやメインのXML定義ファイルを修正するリスクや複雑さを無くすことが出来ます。
以下のXML設定メタデータを見ると、DataSource
はプレースホルダーで定義してあります。この例は外部のProperties
ファイルで設定するプロパティを示しています。実行時にPropertyPlaceholderConfigurer
がメタデータに適用され、DataSourceのプロパティを置換します。置換対象の値は${property-name}
形式のプレースホルダー(placeholders)として指定し、その形式はAnt / log4j / JSP EL styleに従います。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:com/foo/jdbc.properties"/> </bean> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
実際の値は標準JavaProperties
フォーマットの別ファイルにあります。
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
${jdbc.username}
文字列は実行時にsaと置換され、プロパティファイルのキーとマッチする他のプレースホルダーも同じように置換されます。PropertyPlaceholderConfigurer
はビーン定義の多くのプロパティと属性のプレースホルダーをチェックします。よって、プレースホルダーのプレフィクスとサフィックスはカスタマイズ可能です。
Spring 2.5で導入されたcontext
名前空間により、専用の設定要素でプロパティのプレースホルダーを設定可能です。location
属性に一つ以上のロケーションをカンマ区切りリストで設定可能です。
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
PropertyPlaceholderConfigurer
はProperties
ファイルのプロパティだけ参照するわけではありません。デフォルトでは、指定プロパティファイルのプロパティが見つからない場合、JavaSystem
プロパティに対するチェックも行います。この振る舞いはconfigurerのsystemPropertiesMode
プロパティを設定することでカスタマイズ可能で、以下の3つの数値のうち一つを設定します。
- never (0): システムプロパティをチェックしない。
- fallback (1): 指定プロパティファイルで解決不能な場合システムプロパティをチェックする。デフォルト。
- override (2): 指定プロパティファイルを試行する前に、先にシステムプロパティをチェックする。これによりシステムプロパティで他のプロパティソースをオーバーライド可能。
詳細についてはPropertyPlaceholderConfigurer
のjavadocを参照してください。
PropertyPlaceholderConfigurer
はクラス名を置換し、実行時に特定の実装クラスを選びたい場合などに有用です。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <value>classpath:com/foo/strategy.properties</value> </property> <property name="properties"> <value>custom.strategy.class=com.foo.DefaultStrategy</value> </property> </bean> <bean id="serviceStrategy" class="${custom.strategy.class}"/>
実行時にクラスを正しく解決できない場合、non-lazy-initビーンのApplicationContext
のpreInstantiateSingletons()
フェーズにおける、ビーン生成時に解決処理は失敗します。
Example: the PropertyOverrideConfigurer
bean factory post-processorにはPropertyOverrideConfigurer
があり、これはPropertyPlaceholderConfigurer
と似ていますが、後者とは異なり、基になる定義がデフォルト値を持つことも、ビーンプロパティの値を持たない事も出来ます。オーバーライドするProperties
ファイルがビーンプロパティ用のエントリをもたない場合、デフォルトコンテキスト定義が使われます。
注意点として、ビーン定義はオーバーライドされていることを感知しないため、configurerでオーバーライドされることがXML定義ファイルからは必ずしも明確ではありません*27。同一のビーンプロパティに異なる値を定義する複数のPropertyOverrideConfigurer
インスタンスがある場合、オーバーライドのメカニズムに依存して、最後の一つが勝ちます。
プロパティファイル設定の行は以下のフォーマットになります。
beanName.property=value
例は以下の通りです。
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
このサンプルファイルはコンテナ定義においてdataSourceというビーン名で使用可能でdriverとurlのプロパティを持ちます。
最後のプロパティを除くコンポーネントパスが非nullである場合(コンストラクタによって初期化済み)に限り、複合プロパティ名(Compound property names)もサポートします。例は以下の通りです。
foo.fred.bob.sammy=123
foo
ビーンのfred
プロパティのbob
プロパティのsammy
プロパティがスカラー値123
に設定されます。
オーバーライドに指定する値は常にリテラル値で、ビーン参照には変換しません。この規約はXMLビーン定義の基となる値がビーン参照を指定する場合にも適用されます。
Spring 2.5で導入したcontext
名前空間によって、プロパティオーバーライド専用の設定要素が使用可能です。
<context:property-override location="classpath:override.properties"/>
5.8.3 Customizing instantiation logic with a FactoryBean
org.springframework.beans.factory.FactoryBean
インタフェースを実装するオブジェクトはthemselves factoriesとなります。
FactoryBean
インタフェースはSpring IoCコンテナにインスタンス化ロジックを組み込むためのものです。冗長なXMLに対してJavaで表現した方が良い複雑な初期化コードがある場合、自前のFactoryBean
を作成し、そのクラス内に複雑な初期化コードを作り、コンテナにカスタムFactoryBean
を組み込みます。
FactoryBean
は三つのメソッドを提供します。
Object getObject()
: このファクトリーが生成するオブジェクトのインスタンスを返します。インスタンスは共有可能で、このファクトリーがシングルトンかプロトタイプのどちらを返すかに依存します。boolean isSingleton()
:FactoryBean
がシングルトンを返す場合true
、そうでなければfalse
を返します。Class getObjectType()
:getObject()
メソッドが返すオブジェクトの型、もしくは、あらかじめ型を知ることが出来ない場合にはnull
を返します。
FactoryBean
の概念とインタフェースはSpring Framework内の様々な箇所で使われており、Spring自身にはFactoryBean
インタフェースの実装は50個以上含まれています。
ビーンインスタンスではなくそれを生成するFactoryBean
自体をコンテナに問い合わせる場合には、ApplicationContext
のgetBean()
呼び出し時にアンパサンド(&
)をビーンIDの前につけます。
myBean
というIDでFactoryBean
を設定する場合、コンテナ上でのgetBean("myBean")
呼び出しはFactoryBean
の生成結果を返し、一方、getBean("&myBean")
はFactoryBean
のインスタンス自体を返します。
*1:make bean A aware of the containerが原文。aware ofが、~に気付いている、~を知っている、とかの意味で、直訳すれば『コンテナがビーンAの存在を認識する』ぐらい?
*2:You must be careful to deploy the command bean as a prototype, if that is actually what is needed.が原文。カンマ以降のif~が上手く訳せない…
*3:原文はinstead of having to bake in the scope of an object at the Java class level この場合のbakeってインスタンスの生成ってぐらいの意味なんだろうか?レシピに例えてるし、インスタンスを作るのを『焼き上げるbake』)って言ってるんだろうかね
*4:a bean created off the back of a single bean definitionが原文にはあり、この部分は省略している。off the back ofが訳せない。
*5:この図で言うとことの、accountDaoをプロトタイプにすることは一般的ではないが、図はそうなっている。その理由は単に画像をシングルトンのところからコピペした手抜き工事だからだよーん、という程度の意味であろう
*6:All lifecycle management past that point must be handled by the clientが原文。past that pointって…?
*7:なんか各段落で言ってることが矛盾してる気がするんだが……
*8:This makes beans that are request- and session-scoped available further down the call chain.が原文。available further downがだいぶ怪しい訳だが…呼び出しチェーンを下流方向に進める、を、転じて『大本』と訳すことにした
*9:or which there may be several in any given web applicationが原文。誤訳してるかも。
*10:You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes.が原文。でもサンプルだとシングルトンにセッションスコープのインジェクトしてるのだけど…do not needのニュアンスが分からない。
*11:The configuration in the following example is only one lineが原文。実際に重要なのは一行だけ、みたいなニュアンスなんだろうか?直訳だと意味が良くわからん…
*12:bad practice
*13:直訳すれば、オブジェクト破棄を可能にするメソッド、ぐらいな感じ。だけど実際にはこの後にあるように、破棄時のコールバック登録メソッドなんですよね。なんと訳したらいいのやら……
*14:this identifier can be the session identifier.が原文。http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/context/request/SessionScope.html#getConversationId-- によると、the conversation ID would typically be equal to (or derived from) the session ID とあるので、HttpSession#getIdが返ると思われ。
*15:When you place <aop:scoped-proxy/> in a FactoryBean implementation, it is the factory bean itself that is scoped, not the object returned from getObject().が原文。ちょっとどう訳したらいいか分からんかった……
*16:If you don’t want to use the JSR-250 annotations but you are still looking to remove coupling consider the use of init-method and destroy-method object definition metadata.が原文。remove coupling considerってどう訳すのだろうか……?
*17:デジカメとかの写真の生データをraw data、すなわち生データと呼ぶわけだが、ここでは後述されるようにビーンにAOPなど諸々のデコレーションを盛り込む前の『生のビーン』といった意味合いと思われる。
*18:なんかビミョーな日本語だが、Integer.MIN_VALUE would be among the first to start ...で、一方、Integer.MAX_VALUE would indicate that the object should be started last ...と、ビミョーに原文はニュアンスが異なる。最も低いフェーズの依存される側は、他に依存するものが無いハズなので、まず間違いなく最初開始&最後停止になる。逆に、最も高いフェーズは依存する側であり、その依存関係によっては、最後開始&最初停止にならないかもしれない、と予測できる。wouldとindicate that shouldのニュアンスはそんな感じと思われる
*19:http://eow.alc.co.jp/search?q=gracefully 優雅に、潔く、奥ゆかしく、という意味らしい。ニュアンス的には、リソース解放など後処理をキッチリやって飛ぶ鳥跡を濁さず的にお行儀良くシャットダウンする、みたいな感じと思われる
*20:The callback is invoked after population of normal bean properties but before an initialization callback such as InitializingBean afterPropertiesSet or a custom init-method.が原文。前後関係を誤訳している可能性がある。ここが重要な場合は実際に実装を試してみることを推奨します
*21:even if both containers are part of the same hierarchy.が原文。ちょっと訳に自信が無い
*22:意味がよくわからない…
*23:clearly indicating the post-processor nature of that beanが原文。この場合のnatureは性質とかで、もっと言えば『post-processorのビーンの型』だと思う
*24:よくわからん
*25:訳がテキトーだが何が書いてるのか俺自身良く理解してない
*26:An ApplicationContext automatically detects any beans that are deployed into it that implement the BeanFactoryPostProcessor interfaceが原文。こういうthatが複数続く文は相変わらず苦手
*27:so it is not immediately obvious from the XML definition file that the override configurer is being usedが原文。is being usedのあたりはもうちょっと良い訳があるかも