kagamihogeの日記

kagamihogeの日記です。

Spring Framework Reference Documentation 4.1.5のIII. Core Technologies 5.4.6から5.8までをテキトーに訳した

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.

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.

Figure 5.2.

XMLでプロトタイプとしてビーンを定義する例は以下の通りです。

<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>

他のスコープとは対照的に、Springはプロトタイプビーンのライフサイクルを完全には管理しません。コンテナはプロトタイプオブジェクトを、インスタンス化・設定・諸々のアセンブルをしてクライアントに渡しますが、プロトタイプインスタンスに関するそれ以上の記録は行いません。それ故に、initializationライフサイクルコールバックはすべてのスコープの全オブジェクトで呼ばれますが、プロトタイプの場合、設定したdestructionライフサイクルコールバックは呼び出されません。クライアントコードは、プロトタイプスコープオブジェクトのクリーンナップと、プロトタイプビーンが持つ希少リソースを解放する責任があります。プロトタイプスコープビーンが抱えるリソースを解放するためにSpringコンテナを取得するには、クリーンナップの必要があるビーンの参照を持つカスタムbean post-processorの使用を検討してください。

いくつかの点において、プロトタイプスコープのビーンに関するSpringコンテナの役割はJavanew演算子の代わりとなるものです。あるポイントを越えたすべてのライフサイクル管理はクライアントが制御する必要があります。*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”を参照してください。

*7

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のDispatcherServletDispatcherPortletが処理するリクエスト内のスコープ付きビーンにアクセスする場合、特に設定は必要ありません。DispatcherServletDispatcherPortletは関連状態をすべて公開しています。

SpringのDispatcherServletの外側で処理されるリクエスト(たとえばJSFStruts)を用いる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-classfalseに指定します。なお、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と思われます。また、組み込みのsingletonprototypeスコープはオーバーライド不可です

Creating a custom scope

カスタムスコープをSpringコンテナに導入するには、このセクションで解説するorg.springframework.beans.factory.config.Scopeインタフェースを実装します。自前のスコープを実装する方法を知るには、実装の必要があるメソッドの詳細を解説しているScopejavadocSpring 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コンテナの例でいうとsingletonprototypeです。二番目の引数は登録および使用したいカスタム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 InitializingBeanDisposableBeanインタフェースを実装します。コンテナは前者用に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設定で行うには@BeaninitMethod属性を使用し、詳細は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設定で行うには@BeandestroyMethod属性を使用し、詳細は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固有のInitializingBeanDisposableBeanコールバックインターフェースを使わない、初期化および破棄メソッドコールバックを作るには、通常、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-methoddestroy-method属性を使用してメソッド名を(XMLで)指定することでデフォルトをオーバーライドできます。

Springコンテナは、あるビーンのすべての依存性を供給した直後に、設定した初期化コールバックを呼び出すことを保証します。

初期化コールバックはロウビーン参照(raw bean reference)*17で実行しますが、その意味は、AOPインターセプターなどその他諸々はまだビーンに適用していない、ということです。ターゲットビーンをまず始めに完全に生成してから、インターセプターチェーンのAOPプロキシ(など)を適用します。ターゲットビーンとプロキシを別々に定義している場合、プロキシをバイパスして、ロウターゲットビーン(raw target bean)との相互作用が可能です。それ故に、初期化メソッドにインターセプターを適用するのは矛盾しており、なぜなら、プロキシ/インターセプターにターゲットビーンのライフサイクルを結びつけると、raw target beanに直接相互作用する場合におかしな動作となります(leave strange semantics)。

Combining lifecycle mechanisms

Spring 2.5以降では、ビーンライフサイクルの振る舞いを制御する三つのオプションが使えます。InitializingBeanDisposableBeanのコールバックインタフェース、カスタムinit()destroy()@PostConstruct@PreDestroyアノテーション。ビーンを制御するのにこれらのメカニズムを組み合わせて使います。

もし複数のライフサイクルメカニズムをビーンに設定したり、異なるメソッド名でそれぞれのメカニズムを設定した場合、以下に示す順序でそれぞれに設定したメソッドを実行します。ただし、同一のメソッド名を設定した場合、たとえば、初期化メソッド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();

}

LifecycleProcessorLifecycleインタフェースの拡張な点に注意してください。コンテキストのリフレッシュ&クローズに対応する二つのメソッドを追加しています。

startupとshutdownの呼び出し順序が重要な場合があります。ある二つのオブジェクト間に"依存"("depends-on")関係が存在する場合、依存する側は依存性のに開始し、依存性のに停止します。しかし、時には直接的な依存性が不明確なことがあります。ある特定の型のオブジェクトが、別の型のオブジェクトよりも先に開始しなければならないと、開発者だけが知っている場合があるかもしれません。そうした場合、SmartLifecycleインタフェースは別のオプションを定義しており、スーパーインタフェースPhasedgetPhase()メソッドがあります。

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

ApplicationContextorg.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")constructorbyTypeオートワイヤモード(Section 5.4.5, “Autowiring collaborators”で解説したもの)ではセッターメソッドないしコンストラクタ引数のApplicationContext型で依存性を入れられます。より柔軟なやり方としては、複数パラメーターメソッドとオートワイヤフィールド機能など、新しいアノテーションベースのオートワイヤ機能を使います。対象となるフィールド・コンストラクタメソッド@Autowiredアノテーションを持つ場合、ApplicationContext型を期待するフィールド・コンストラクタ引数・メソッドパラメータへ、ApplicationContextがオートワイヤされます。詳細についてはSection 5.9.2, “@Autowired”を参照してください。

ApplicationContextorg.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

上述のApplicationContextAwareBeanNameAwareに加え、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 ApplicationContexts でのみ利用可能 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の実行順序を制御できます。BeanPostProcessorOrderedインタフェースを実装する場合のみこのプロパティは設定可能です。そのため、自前のBeanPostProcessorを作る場合にはOrderedインタフェースを実装することも考慮に入れてください。より詳しい詳細については、BeanPostProcessorOrderedjavadocを参照してください。また、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として実装しているものがあります。

ApplicationContextBeanPostProcessorインタフェースを実装する設定メタデータで定義したビーンを自動検出(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をコピーする場合に有用です。注意点として、プログラム的に追加したBeanPostProcessorsOrderedインタフェースを考慮しません(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

次にApplicationContextBeanPostProcessorsの使用・登録・作成方法の例を示します。

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の実行順序を制御できます。ただし、BeanFactoryPostProcessorOrderedインタフェースを実装する場合に限りorderプロパティは設定可能です。自前のBeanFactoryPostProcessorを作成する場合、Orderedインタフェースの実装も考慮に入れて下さい。BeanFactoryPostProcessorOrderedインタフェースの詳細についてはjavadocを参照してください。

実際のビーンインスタンス(設定メタデータを基に生成したオブジェクトのこと)を変更したい場合、BeanPostProcessorSection 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には、PropertyOverrideConfigurerPropertyPlaceholderConfigurerなどの、定義済みbean factory post-processorsがいくつか含まれています。BeanFactoryPostProcessorのカスタム実装では、たとえば、カスタムプロパティエディターを登録して使用したりすることが出来ます。

ApplicationContextBeanFactoryPostProcessorインタフェースを実装するビーンを自動検出します*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"/>

PropertyPlaceholderConfigurerPropertiesファイルのプロパティだけ参照するわけではありません。デフォルトでは、指定プロパティファイルのプロパティが見つからない場合、JavaSystemプロパティに対するチェックも行います。この振る舞いはconfigurerのsystemPropertiesModeプロパティを設定することでカスタマイズ可能で、以下の3つの数値のうち一つを設定します。

  • never (0): システムプロパティをチェックしない。
  • fallback (1): 指定プロパティファイルで解決不能な場合システムプロパティをチェックする。デフォルト。
  • override (2): 指定プロパティファイルを試行する前に、先にシステムプロパティをチェックする。これによりシステムプロパティで他のプロパティソースをオーバーライド可能。

詳細についてはPropertyPlaceholderConfigurerjavadocを参照してください。

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ビーンのApplicationContextpreInstantiateSingletons()フェーズにおける、ビーン生成時に解決処理は失敗します。

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というビーン名で使用可能でdriverurlのプロパティを持ちます。

最後のプロパティを除くコンポーネントパスが非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自体をコンテナに問い合わせる場合には、ApplicationContextgetBean()呼び出し時にアンパサンド(&)をビーン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のあたりはもうちょっと良い訳があるかも