Springの中で最も基本となる重要な2つのパッケージはorg.springframework.beans
パッケージとorg.springframework.context
パッケージだ。このパッケージに含まれているコードではSpringのInversion of Control(Dependency Injectionと呼ぶ人もいる)機能が提供されている。これに含まれているBeanFactory
により先進的なコンフィグレーションメカニズムが提供されており、Dependency Injectionと最近このパターンに名付け出した人々もいる(これに関する情報については、2.1章「Inversion of Control / Dependency Injection」を参照して欲しい)。このBeanFactoryではいろんな種類のストレージファシリティを潜在的に利用してどんなビーンでも運用が可能な先進的なコンフィグレーションメカニズムが用意されている。このApplicationContextはBeanFactory
(これはサブクラスである)の上位に構築され、SpringのAOP機能や(i18nを用いた)メッセージング、他のコンテキストから継承したコンテキストを持たせたり、WebApplicationContext
のようなアプリケーションレイヤ独自のコンテキストを定義することが可能だ。
要するに、このBeanFactory
では設定を行うためのフレームワークと基本的な機能性を提供していて、例えApplicationcontext
に機能が拡張されていても,そのいくつかはおそらくよりJ2EEやエンタープライズ向けのものだ。一般的に、ApplicationContext
は完全BeanFactory
のスーパーセットであり、BeanFactory
でできることや振る舞いに関する記述はどれもApplicationContext
にも当てはまるとみなすべきである。
ユーザはその特定の状況でBeanFactory
かApplicationContext
のどちらを使うのが適しているのかわからないことがある。通常、J2EE環境でアプリケーションを構築する場合、ApplicationContext
を用いるのがベストな選択肢だ。というのは、ApplicationContext
ではBeanFactory
の全部の機能を使うことができるし、さらに機能が追加されているからだ。他にもいくつかの機能を用いる上で一般的に望ましいより宣言的なアプローチが使えるからだ。BeanFactory
を使ったほうが好ましい使用例というのは、(残り1キロバイトが重要なアプレットのような)メモリの使い方がシビアな場合や、ApplicationContext
の全ての機能を必要としない場合だ。
本チャプターではBeanFactory
とApplicationContext
の両方に関係する事柄を扱う。BeanFactory
のみに言及している場合には、その文章はApplicationContext
にも当てはまるとみなしていただいて構わない。ApplicationContext
でのみ利用可能な機能の場合はそのことを明示してある。
BeanFactoryは数多くのビーンを初期化して、設定して管理を行うコンテナだ。これらビーンはお互いに協調して動作し、お互いに依存関係を持っている。この依存性BeanFactory
によって利用される設定データに反映されている(でも、一部には設定データとして表現されず、ランタイム時にビーン間の相互作用としてプログラムで記述される機能もある)。
BeanFactory
はorg.springframework.beans.factory.BeanFactory
インタフェースによって表され、その実装は多数用意されている。最も一般的に用いられる単純なBeanFactory
の実装は、org.springframework.beans.factory.xml.XmlBeanFactory
だ。(これは、ApplicationContext
がBeanFactory
のサブクラスであり、ほとんどのユーザは結局ApplicationContext
のXML派生を使っているということだ)。
ほとんどのシナリオについて、BeanFactory
で管理されたほとんど全てのユーザコードはBeanFactory
を意識してはいけないが、どうにかしてBeanFactory
を初期化しなければならない。これは下記のようにしてユーザコードから明示的に行うことができる。
Resource res = new FileSystemResource("beans.xml"); XmlBeanFactory factory = new XmlBeanFactory(res);
あるいは、
ClassPathResource res = new ClassPathResource("beans.xml"); XmlBeanFactory factory = new XmlBeanFactory(res);
あるいは、
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml", "applicationContext-part2.xml"}); // of course, an ApplicationContext is just a BeanFactory BeanFactory factory = (BeanFactory) appContext;
注:ひとたび本章からビーンファクトリやアプリケーションコンテキストの基本を学んだら、4章の低レイヤへの抽象アクセスに記載されているSpringのリソース抽象化を調べるのも役に立つだろう。ロケーションパスやApplicationContext
のコンストラクタに渡されるパスは実際にはリソース文字列が簡単な形式になっており、特定のコンテキストの実装に適切に割当られる(例えば、ClassPathXmlApplicationContext
は単純なロケーションパスをクラスパスロケーションとして扱う)。しかし、実際のコンテキスト型がどうであれ、クラスパスやURLから強制的に定義をロードするための特別なプレフィックスを使うことも可能である。これとは別の特別なプレフィクスである、classpath*:
は、コンテキストを構築するのに、見つけて組み合わせるためのクラスパス上で同じ名前のコンテキスト定義ファイルをすべて使うことができる。より詳細な情報については、リソースに関する章を参照してほしい。
多くの利用例では、ユーザコードでBeanFactory
やApplicationContext
を初期化する必要はない。というのはSpring Frameworkでこれを行っているからである。例えば、ウェブ層では、J2EEのWebアプリケーションの通常の起動プロセスの一部としてSpringのApplicationContext
を自動的にロードするためのコードが提供されている。(3.19 "ウェブアプリケーションからApplicationContextを生成する"を参照のこと)。
BeanFactory
をプログラム的に操作することに関しては後述する。次のセクションではBeanFactory
の設定について焦点を当てる。
BeanFactory
の設定は、最も基礎的なレベルには、BeanFactory
が管理しなければならないビーンの定義により構成される。XmlBeanFactory
では、トップレベルのbeans
要素の中に複数のbean
要素が構成されている。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" \ "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="..." class="..."> ... </bean> <bean id="..." class="..."> ... </bean> ... </beans>
(XmlBeanFactory
のような)DefaultListableBeanFactory
の派生の内部にあるビーン定義はBeanDefinition
オブジェクトとして表現される。これには、(他の情報と合わせて)下記のような詳細が含まれている。
上記にリストした概念は直接ビーン定義を構成する要素の組み合わせに変換される。これらの要素のうちのいくつかは、各々に関連するドキュメントへのリンクといっしょに下記に挙げておく。
機能 | 詳細情報 |
---|---|
クラス | 節[3.2.3 ビーンクラス] |
idや名前 | 節[3.2.4 ビーン識別子(IDと名前)] |
シングルトンもしくはプロトタイプ | 節[3.2.5 シングルトンにするかそれともしないか] |
コンストラクタ引数 | 節[3.3.1 ビーンプロパティの設定とコラボレータ] |
ビーンプロパティ | 節[3.3.1 ビーンプロパティの設定とコラボレータ] |
autowireモード | 節[3.3.6 コラボレータをオートワイヤリングする] |
依存性チェックモード | 節[3.3.7 依存関係をチェックする] |
初期化メソッド | 節[3.4.1 ライフサイクルインタフェース] |
デストラクタメソッド | 節[3.4.1 ライフサイクルインタフェース] |
ビーン定義は内部的にはorg.springframework.beans.factory.config.BeanDefinition
インタフェースや、そのさまざまな実装(Root/ChildBeanDefinition
)で表されていている。しかしながら、ほとんどのユーザコードがBeanDefinition
と一緒に動くということはほとんどない。ユーザコードがBeanDefinition
オブジェクトと一緒に直接動作することはほとんどない。通常、ビーン定義は(XMLのような)起動時に読み込まれるメタデータフォーマットで表現される。このようなビーン定義は、内部ではファクトリ内にあるBeanDefinition
オブジェクトで表現される。
特定のビーンの生成法に関する情報が含まれているビーン定義とあわせて、BanFactory
の実装にファクトリの外部で(独自コードにより)生成された既存のオブジェクトの登録が可能だ。BeanFactory
には、生成法についての情報がわかっている特定のビーン定義だけでなく、ファクトリの外部で(独自のコードにより)生成される既存のビーンオブジェクトも登録することができる。DefaultListableBeanFactory
ではこの機能を、org.springframework.beans.factory.config.ConfigurableBeanFactory
インタフェースで定義されているように、registerSingleton
メソッドによってサポートしている。でも、典型的なアプリケーションでは純粋にメタデータビーン定義によるビーン定義を使って行っている。
クラス属性は通常、マンダトリ(セクション3.2.3.3「インスタンスファクトリメソッドによるビーンの生成」と、セクション3.5「アブストラクトビーン定義、子ビーン定義」を参照のこと)であり、2つの目的のうちの1つのために利用される。BeanFactory
自身が直接コンストラクタを呼ぶことによりビーンを生成する(Javaコードがnewを呼ぶのと同じ)という最も一般的なケースでは、クラス属性は生成されたビーンのクラスが指定されている。これほどは一般的ではないが、BeanFactory
が静的な、ファクトリメソッドと呼ばれるそのクラスに定義されているメソッドを呼んでビーンを生成する場合は、クラス属性には、その静的なファクトリメソッドを含んでいるクラスが指定される(その静的ファクトリメソッドから返されるビーンの型は同じクラスかもしれないし別のクラスかもしれないが、それは重要ではない)。
コンストラクタによる方法を用いてビーンを生成する場合、通常のクラスは全てSpringで利用可能であり、互換性がある。すなわち、生成されたクラスは特定のインタフェースが実装されていたり、特定の方法でコーディングされている必要はないのである。ビーンクラスを単に指定するだけで十分なのだ。しかしながら、その特定のビーンに利用するいづれかのIoCに依存するのであれば、デフォルト(空の)コンストラクタが必要になるかもしれない。
さらに、そのBeanFactory
はJavaBeansだけを管理するだけではなく、管理させたい全てのクラスの管理を行うことが可能なのだ。Spring を使っているほとんどの人は、実際には(デフォルト(引数を持たない)コンストラクタとプロパティに基づいた適切なセッターやゲッターをもつ)JavaBeansをBeanFactory
で保持することを好むが、それだけでなくもっと斬新な非ビーンスタイルのクラスをBeanFactory
に保持してもかまわないのである。もし、例えば、JavaBean仕様に完全には準拠しないレガシーなコネクションプールを使用する必要があっても、Springでは同じように管理することができるのだ。
XmlBeanFactory
を使えば、ビーンクラスは以下のように指定することができる。
<bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
コンストラクタに(オプション)引数を供給するメカニズム、あるいはオブジェクトインスタンスが生成された後でプロパティが設定されるメカニズムについて簡単に述べる。
静的なファクトリメソッドを使って生成されるビーンを定義する場合、その性的なファクトリメソッドを含んだクラスを指定するクラス属性に加えて、他のfactory-method
という名前の属性がファクトリメソッドを指定するのに必要とされる。Springではこのメソッド(と後述するオプションの引数リスト)が呼び出し可能であり、実際のオブジェクトを戻すことができることが期待されている。このオブジェクトはその時点から、あたかも普通にコンストラクタかあ生成されたかのように扱うことができる。そのようなビーン定義のための1つの方法は静的なファクトリをレガシーコードの中で呼ぶことだ。
<bean id="exampleBean" class="examples.ExampleBean2" factory-method="createInstance"/>
ファクトリメソッドに(オプションの)引数を供給する、もしくはファクトリから返された後でそのオブジェクトにプロパティを設定するためのメカニズムについては後述する。
インスタンスの(静的でない)ファクトリメソッドを使うのは、静的なファクトリメソッドを使ってビーンを生成するのと全く同じで、そのファクトリから既存のビーンのファクトリメソッドが新しいビーンを生成するために呼ばれる。
このメカニズムを使うために、そのクラスの属性が空でないといけない。また、factory-bean
属性にカレントの、あるいはそのファクトリメソッドをもっている祖先のビーンファクトリのビーン名が指定されていなければならない。このファクトリメソッド自身は(下記の例にあるように)factory-method
属性により設定される。
<!-- The factory bean, which contains a method called createInstance --> <bean id="myFactoryBean" class="..."> ... </bean> <!-- The bean to be created via the factory bean --> <bean id="exampleBean" factory-bean="myFactoryBean" factory-method="createInstance"/>
ビーンにはどれにでも1つあるいは複数ID(identifierとかnameとか呼ぶこともあるが全部同じもののことだ)がある。このidはそのビーンがホスティングされているBeanFactory
あるいはApplicationContext
毎に一意でないといけない。あるビーンはIDを1つしか持っていないが、2つ以上のIDを持っている場合、余分は本質的にはエイリアスとみなす。
XmlBeanFactory
(ApplicationContext
の派生も含めて)では、id
かname
属性をビーンIDを指定するのに使う。このid
属性によってIDを1つ指定することができて、XML DTD(定義文書)で実際のXML要素のID属性が指定されているように、他の要素からこの要素に指し戻る場合、パーザは特別な検証を行うことができる。よって、これはビーンIDを指定するのに望ましい方法だ。しかしながら、XML仕様ではXML IDで有効な文字が制限されている。実際問題としては通常は制約にならないが、制限されている文字を使いたい、あるいはビーンに他のエイリアスを導入したいという必要が生じた場合(name
属性からコンマかセミコロン、空白で区切られた)1つ以上のビーンIDを代わりに指定してもよい。
ビーン名をつけることは必須ではない、という点に注意してほしい。名前が明示的につけられてない場合、コンテナは前述のビーンに(ユニーク)な名前を生成する。ビーンに名前をつけない理由については、( 豆の名前を供給することは要求されないことに注意してください。名前が明示的に供給されない場合、コンテナーは前述の豆の(ユニーク)名前を生成するでしょう。豆の名前を供給しない動機は、その後(1つの使用ケースは内部の豆です)議論されるでしょう。
ビーンはシングルトンか非シングルトンか2つのうちのどちらかのモードで配備されるように定義される。(後者は、プロトタイプとも呼ばれている。この用語はどうもしっくりこないので厳密に使われるわけではないが)。あるビーンがシングルトンの場合、そのビーンの共有インスタンスが1つだけ管理され、このビーンに対するビーン定義にマッチする1つあるいは複数のIDつきの全てのリクエストはその1つの特定のビーンインスタンスに基づいて値が返されることになる。
非シングルトン、プロトタイプモードのビーン配備は新しいビーンインスタンスそのビーンに対してリクエストされる毎に生成される。これは例えば各ユーザが独立したユーザオブジェクトやそれに似たものを必要とする場合は理想的だ。
ビーンは非シングルトンを指定しない限りデフォルトではシングルトンモードで配備される。非シングルトン(プロトタイプ)へタイプを変更することによってビーンに対してリクエスト毎に新しくビーンを生成するようになり、望んでいるものではなくなるかもしれないことは心に留めておいて欲しい。従ってプロトタイプへモードを変更するのは確実に必要であるときだけだ。
下記の例では、2つのビーンが、一方ははシングルトンとして定義され、他方は非シングルトン(プロトタイプ)であると宣言されている。exampleBean
は毎回クライアントがこのビーンのBeanFactory
にリクエストするたびに生成され、ここで、yetAnotherExample
は1回しか生成されない。つまり厳密に同じインスタンスへのリファレンスがこのビーンへのリクエストの度に返される。
<bean id="exampleBean" class="examples.ExampleBean" singleton="false"/> <bean name="yetAnotherExample" class="examples.ExampleBeanTwo" singleton="true"/>
注:プロトタイプモードでビーンをデプロイする場合、ビーンのライフサイクルは若干変更される。定義によって、Springは非シングルトン/プロトタイプビーンのライフサイクルを完全に管理することはできない。生成された後、クライアントに渡され、コンテナはその跡を追いかけるようなことはしないからだ。非シングルトン/プロトタイプビーンを「new」オペレータの置き換えとして話をするとSpringの役割を考えることができる。そのポイントを経過したライフサイクルの様相はクライアントで処理されなければならないのだ。BeanFactory
にあるビーンのライフサイクルについては、セクション3.4.1 「ライフサイクルインタフェース」にて詳細に触れる。
Inversion of ControlはもうDependency Injectionと呼ばれている。この基本原理は、ビーンはその依存性(つまり、いっしょに動作する他のオブジェクト)をコンストラクタ引数か、ファクトリメソッドへの引数、あるいは生成後のオブジェクトインスタンスあるいはファクトリメソッドから返されたオブジェクトインスタンスに設定されるプロパティでしか定義しないということだ。従って、ビーンを生成するときにこの依存性を実際に注入するのはコンテナの仕事なのだ。これは基本的に、直接クラスのコンストラクタあるいは何かサービスロケータのようなものを使ってビーンのインスタンス化あるいは依存性の配置を行うことの正反対(これがInversion of Controlという名前の下になっている)なのだ。我々はDependency Injectionの利点についてあまり詳しく述べるつもりはないので、ビーンが依存性を見なければコードがより見通しよくなり、疎結合性を高めることもとても簡単になる、ということは使っている中で明らかになる。しかし、依存性が提供され、加えて、その依存性がどこにあってそれは実際にはどんなタイプなのかは分からない。
前のパラグラフで触れたように、Inversion of Control/Dependency Injectionには主要な派生が2つある。
BeanFactory
で定義されたビーンは真のJavaBeanだ。Springでは通常setterベース依存性注入を使うよう主張している。というのは、コンストラクタの引数が増えると、特にプロパティのいくつかがオプション扱いであれば使いづらくなってしまうからだ。
BeanFactory
ではこのどちらの派生でも管理しているビーンに注入するのをサポートしている。(実際には、コンストラクタ方式で依存性が適用された後でsetterベースの依存性の注入もサポートしている。)依存性に関する設定はBeanDefinition
の形をしており、これはプロパティをあるフォーマットから別のフォーマットへ変換する方法を知るためにJavaBeansのPropertyEditor
といっしょに利用される。実際に渡される値は最終的にPropertyValue
オブジェクトの形式になる。しかしながら、Springのユーザのほとんどはこのクラスを直接は(つまり、プログラム的には)使わない。それよりも内部でこれらのクラスのインスタンスに変換されるXML定義ファイルを用意して完全なBeanFactory
やApplicationContext
をロードするのに使う。
ビーンの依存性解決は通常以下のように行われる。
BeanFactory
はビーンについて全てを記述した設定を使って生成され初期化される。Springユーザのほとんどは、XMLフォーマットの設定ファイルをサポートしているBeanFactory
かあるいはApplicationContext
の派生を使っている。
BeanFactory
にある他のビーンへのリファレンスだ。ApplicationContext
の場合は、このリファレンスが親のApplicationContext
にあるビーンへのリファレンスの場合もある。
BeanFactory
の派生(ApplicationContext
の派生も含む)では、ListやMap,Set、それにPropertyコレクション型の定義がサポートされている。さらに、Springではstring型の値を他の任意の型に変換できるようにJavaBeans PropertyEditor
定義を使う。(独自のカスタム型へ変換できるように独自のPropertyEditor
定義を使ったBeanFactory
を用意することもできる。PropertyEditor
に関するもっと詳しい情報や自分で独自に何か追加する方法はセクション3.9の「カスタムエディタを追加して登録する」にある)。ビーンプロパティがJavaのクラス型であれば、Springではそのプロパティにクラス名を表す文字列を指定することができる。またClassEditor PropertyEditor
が用意されているのでこのクラス名を実際のクラスインスタンスへ変換するのに使うことができる。
BeanFactory
が生成される際に、BeanFactory
中の各ビーンの設定をSpringが検証するのを有効にすることは重要だ。これには、ビーンリファレンスが実際に正しいビーンを参照するプロパティであるかどうか(つまり、参照されているビーンもBeanFactory
で定義されているか、もしくはApplicationContext
の場合は親コンテキストで定義されているか)の検証も含んでいる。しかしながら、このビーンプロパティ自体はビーンが実際に生成されるまではセットされない。(ApplicationContext
のシングルトンビーンのように)シングルトンで前もってインスタンス化されるように設定されている場合、ビーンの生成はBeanFactory
生成時に行われるが、そうでなければ、ビーンがリクエストを受けたときにしか行われない。あるビーンが実際に生成されるべきときに、このビーンの依存性とこの依存性の依存性(以下略)が生成され、値が代入されるため、生成されるべき他のビーンへのグラフが潜在的に生成されることになるのだ。
BeanFactory
ロード時のコンフィグ問題を取り上げよう。実際にはプロパティの設定や依存関係の解決(つまり、必要であれば依存関係を生成すること)は可能な限り遅らせられ、ビーンが実際に生成された時だ。これはつまり、正しくロードされたBeanFactory
がその後ビーンを要求した時にもし、そのビーンかあるいは依存関係の1つを生成するのに問題が発生した場合に例外を投げることができるということだ。これは、例えばプロパティが足りないとか間違っていた場合の結果としてこのビーンが例外をthrow
すれば起り得る。こうして設定上の問題が発生した際に知らせるのをこの潜在的に遅らせるのは、ApplicationContext
がデフォルトでは前もってインスタンス化されるシングルトンビーンだからだ。実際に必要になる前にビーンを生成しておくためのある程度の時間メモリの先行投資を行うことによって設定ミスをApplicationContext
が生成された際にすぐさま見つけられるようにしている。必要であればこのデフォルト動作をオーバライドしてシングルトンビーンのいくつかを(あらかじめ生成しておくのではなく)後からロードするようにすることも可能だ。例:
最初は、setterベースインジェクションのBeanFactory
を使った例だ。下記はビーン定義をいくつか指定しているXMLBeanFactory
設定ファイルのほんの一部だ。その次は適切なsetterが宣言してある実際のメインビーンのコードである。
<bean id="exampleBean" class="examples.ExampleBean"> <property name="beanOne"><ref bean="anotherExampleBean"/></property> <property name="beanTwo"><ref bean="yetAnotherBean"/></property> <property name="integerProperty"><value>1</value></property> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; } public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; } public void setIntegerProperty(int i) { this.i = i; } }
これで分かるように、setterがXMLファイルで指定されているプロパティに一致するように宣言されている。(このXMLファイルからのプロパティは直接RootBeanDefinition
からPropertyValues
オブジェクトへの関連を持っている)
これはIoCタイプ3(コンストラクタベースのDependency Injection)を使ったBeanFactory
の例だ。下記は、コンストラクタ引数を指定するXML設定の断片とそのコンストラクタの実際のビーンのコードである。
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg><ref bean="anotherExampleBean"/></constructor-arg> <constructor-arg><ref bean="yetAnotherBean"/></constructor-arg> <constructor-arg type="int"><value>1</value></constructor-arg> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean(AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; } }
これで分かるように、ビーン定義で指定されているコンストラクタ引数はExampleBean
のコンストラクタに引数として渡されるのに使われている。
それでは、コンストラクタを使う代わりに、Springがオブジェクトのインスタンスを返す静的なファクトリメソッドを呼ぶように指示された一例について見てみることにしよう。
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance"> <constructor-arg><ref bean="anotherExampleBean"/></constructor-arg> <constructor-arg><ref bean="yetAnotherBean"/></constructor-arg> <constructor-arg><value>1</value></constructor-arg> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean { ... // a private constructor private ExampleBean(...) { ... } // a static factory method // the arguments to this method can be considered the dependencies of the bean that // is returned, regardless of how those arguments are actually used. public static ExampleBean createInstance( AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { ExampleBean eb = new ExampleBean(...); // some other operations ... return eb; } }
静的なファクトリメソッドへの引数はcontructor-arg
要素で提供され、確かにコンストラクタが実際に使われるのと同じであるという点に注意してほしい。この引数はオプションだ。さらに、ファクトリメソッドから返されているクラスの型は静的ファクトリメソッドを含んでいるクラスと同じ型である必要はないという点を認識することは重要だ。この例では同じではあるが。前述した、インスタンスの(静的でない)ファクトリメソッドは(クラス属性の代わりにfactory-bean
属性で利用されていることから)本質的に同じ方法なので、詳細は割愛する。
コンストラクタ引数解決(訳注:Constructor argument resolution)は引数の型を使ってマッチングをとる。他のビーンが参照されていれば、型がわかるのでマッチングをとることができる。<value>true</value>のような単純な型が使われていれば、Springでは値の型を決定できることができず、そのままでは型によるマッチングをとることができない。下記のクラスで考えてみよう。このクラスは、この後の2つのセクションでも利用する。
package examples; public class ExampleBean { private int years; //No. of years to the calculate the Ultimate Answer private String ultimateAnswer; //The Answer to Life, the Universe, and Everything public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; } }
上述したシナリオは、コンストラクタ引数のtype
属性を使って明示的に指定することにより型のマッチングを行うことができる。下記はその例である。
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int"><value>7500000</value></constructor-arg> <constructor-arg \ type="java.lang.String"><value>42</value></constructor-arg> </bean>
コンストラクタ引数には、index
属性を使って明示的に指定されたインデックスを持たせることができる。下記はその例である。
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0"><value>7500000</value></constructor-arg> <constructor-arg index="1"><value>42</value></constructor-arg> </bean>
単純な値が複数ある場合のあいまい性の問題を解決するのと同様、インデックスを指定するのもコンストラクタに同じ型の引数が2つある場合のあいまい性の問題を解決する。このインデックスは0から始まる点については注意してほしい。
コンストラクタ引数インデックスを指定するのは、コンストラクタIoCを使うのに好ましい方法である。
前の章で述べたように、ビーンプロパティやコンストラクタ引数を、他の管理されたビーン(コラボレータ)へのリファレンスやインラインで定義された値で定義することができる。XmlBeanFactory
はこの用途のためにproperty
やconstructor-arg
要素をもつ多くのsub-element
型をサポートする。
value
要素は人が判読可能な文字列表現としてプロパティやコンストラクタ引数を指定する。先に詳細に触れたように、JavaBeansのPropertyEditors
はこの文字列の値をjava.lang.String
から実際のプロパティや引数の型へ変換するのに用いられる。
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" \ destroy-method="close"> <!-- results in a setDriverClassName(String) call --> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/mydb</value> </property> <property name="username"> <value>root</value> </property> </bean>
ヌル要素は、null値を扱うのに用いる。Springではプロパティや同種ものに空の引数を空文字列として扱う。以下はXmlBeanFactory
の設定だ。
<bean class="ExampleBean"> <property name="email"><value></value></property> </bean>
この結果、emailのプロパティにはexampleBean.setEmail("")というjavaのコードと同じく、""が設定される。この特別な<null>要素はnull値をあらわすのに用いられる。したがって、
<bean class="ExampleBean"> <property name="email"><null/></property> </bean>
は、exampleBean.setEmail(null)というjavaのコードと同値である。
list
、set
、map
、props
の要素は、定義や値の設定にList
、Set
、Map
、Properties
というJavaの型をもつプロパティや引数を指定してもよい。
<bean id="moreComplexObject" class="example.ComplexObject"> <!-- results in a setPeople(java.util.Properties) call --> <property name="people"> <props> <prop key="HarryPotter">The magic property</prop> <prop key="JerrySeinfeld">The funny property</prop> </props> </property> <!-- results in a setSomeList(java.util.List) call --> <property name="someList"> <list> <value>a list element followed by a reference</value> <ref bean="myDataSource"/> </list> </property> <!-- results in a setSomeMap(java.util.Map) call --> <property name="someMap"> <map> <entry> <key><value>yup an entry</value></key> <value>just some string</value> </entry> <entry> <key><value>yup a ref</value></key> <ref bean="myDataSource"/> </entry> </map> </property> <!-- results in a setSomeSet(java.util.Set) call --> <property name="someSet"> <set> <value>just some string</value> <ref bean="myDataSource"/> </set> </property> </bean>
map
のキー値、value
値、もしくはset
値のいづれも任意の要素になりうる点に注意してほしい:
(bean | ref | idref | list | set | map | props | value | null)
property
要素内部のbean
要素はBeanFactory
のどこかで定義されたビーンを参照する代わりにビーンの値をインラインに定義するのに用いる。このインラインビーン定義には定義済みのidを指定しなくてもよい。
<bean id="outer" class="..."> <!-- Instead of using a reference to target, just use an inner bean --> <property name="target"> <bean class="com.mycompany.PersonImpl"> <property name="name"><value>Tony</value></property> <property name="age"><value>51</value></property> </bean> </property> </bean>
シングルトンフラグや任意のid属性はちゃんと無視されることに注目してほしい。内部ビーンは匿名のプロトタイプだ。
idref
要素は単に プロパティに文字列idかコンテナ中の他のビーン名を指定するための略記、あるいはエラー防止法だ。
<bean id="theTargetBean" class="..."/> <bean id="theClientBean" class="..."> <property name="targetName"> <idref bean="theTargetBean"/> </property> </bean>
これは、実行時には、以下のコード片と厳密に等価だ。
<bean id="theTargetBean" class="..."> </bean> <bean id="theClientBean" class="..."> <property name="targetName"> <value>theTargetBean</value> </property> </bean>
第一の形式が2つめの形式に比べて優れている主な理由は、idref
タグを使っていることで、Springがデプロイ時に、他のビーンが実際に存在していることを検証できるからだ。2つ目の方では、targetName
というプロパティが強制的に検証されるのと、それがおそらくコンテナが実際にデプロイされてからずっと後にクラスがSpringにより実際にインスタンス化された時にしか検証されないのだ。
さらに、もしその参照されているビーンが実際に同じXMLファイルにあって、そのビーン名がビーンIDであれば、ローカル属性が使われ、XMLパーザによってそのビーン名がXMLドキュメントが解析される時点で検証できるようになる。
<property name="targetName"> <idref local="theTargetBean"/> </property>
このref
要素はproperty
定義要素中で許される最後の要素だ。これは、指定されたプロパティの値に、コンテナで管理されているほかのビーン、つまりコラボレータへの参照を指定するのに利用する。先のセクションで述べたように、referred-to
で指定されたビーンはプロパティが設定されたビーンの依存関係であると見なされ、必要に応じてオンデマンドでプロパティが設定されるよりも前に初期化される(もし、シングルトンビーンであれば、コンテナによりすでに初期化されているはずだ)。全てのリファレンスは究極的には、他のオブジェクトへの参照であるが、他のオブジェクトのID,あるいは名前を指定する方法には3通りあり、そのどれかはどのようにスコープや検証が扱われるかによって決まる。
ref
タグのビーン属性を使ってターゲットビーンを指定するのは最も一般的な形式であり、これにより同じBeanFactory/ApplicationContext
あるいは、親のBeanFactory/ApplicationContext
のビーンへの参照(同じXMLファイル中にあろうとなかろうと)を生成できるようになる。そのbean
属性の値はターゲットビーンのid
属性かあるいはターゲットビーンのname
属性の値の中のどれかと同じになる。
<ref bean="someBean"/>
local
属性を用いてターゲットのビーンを指定することは、XMLパーザが同じファイルにあるXMLのid
参照の検証が可能になるのを利用している。local
属性の値はターゲットビーンのid
属性と同じでなければならないのだ。同じファイルの中にマッチする要素が見つからなければXMLパーザはエラーを検出する。なので、ターゲットビーンが同じXMLファイル中にあんるのであれば、(できるだけ早くエラーを知るために)local
を使う方法が一番いい方法なのだ。
<ref local="someBean"/>
parent
属性を使ってターゲットビーンを指定すると、カレントのBeanFactory
(もしくはApplicationContext
)の親のBeanFactory
(もしくはApplicationContext
)にあるビーンへの参照が生成できるようになる。このparent
属性の値は、ターゲットビーンのid
属性かあるいはターゲットビーンのname
属性のうちの1つと同じものになり、そのターゲットビーンは親のBeanFactory
かApplicationContext
中になければならない。このビーンリファレンス方式の主な用途は、親コンテキストにある既存のビーンをある種のプロキシ(これは親と同じ名前を持っている)でラップする必要がある場合や、ラップされているためにオリジナルのオブジェクトを必要とする場合だ。
<ref parent="someBean"/>
それは値あるいは豆参照を形成する必要があるのに非常に一般的です、全価格および審判要素を使用するほど冗長でないいくつかの近道形式が存在します。特性、建設者-argおよびエントリー要素はすべて、全価格要素を埋め込む代わりに使用されるかもしれない値属性を支援します。したがって下記:
ある値やビーンリファレンスを設定する必要が生じることはよくあることであり、そのためにvalue
やref
要素を全部書かなくてもいい短縮形が用意されている。property
、constructor-arg
およびentry
要素はすべてvalue
属性をサポートしており、すべて書かないといけないvalue
要素の代わりに利用することができる。従って下記:
<property name="myProperty"> <value>hello</value> </property <constructor-arg> <value>hello</value> </constructor-arg> <entry key="myKey"> <value>hello</value> </entry>
は、以下と等価である。
<property name="myProperty" value="hello"/> <constructor-arg value="hello"/> <entry key="myKey" value="hello"/>
通常、手で定義をタイプする場合、より冗長性の少ない省略形の方を使いたいと思うだろう。
このプロパティやconstructor-arg
要素ではフルにネストされたref
要素の代わりに、同様の省略形のref
属性がサポートされている。したがって、下記:
<property name="myProperty"> <ref bean="myBean"> </property <constructor-arg> <ref bean="myBean"> </constructor-arg>
は、以下と等価である。
<property name="myProperty" ref="myBean"/> <constructor-arg value="myBean"/>
しかしながらこの短縮形が<ref bean="xxx">と等価であっても、<ref local="xxx">の短縮形は存在しない、という点に注意して欲しい。ローカルのref
の検証を強化するために、長い形式を使う必要がある。
最後に、このentry
要素ではmap
のキーや値を指定するのに、key/key-ref
やref/value-ref
属性の形式で、短縮形が許されている。従って下記:
<entry> <key><ref bean="myKeyBean"/></key> <ref bean="myValueBean"/> </entry>
は、下記と等価である。
<entry key-ref="myKeyBean" value-ref="myValueBean"/>
再度、この短縮形は、<ref bean="xxx">要素と等価であり、<ref local="xxx">の短縮形は存在しない。
ビーンプロパティを設定する際に、最終的なプロパティ名がNULLでない場合を除いてすべてのコンポーネントのパスと同様、入れ子のプロパティ名やその組み合わせはすべて有効であることに注意してほしい。例えば、下記のビーン定義において、
<bean id="foo" class="foo.Bar"> <property name="fred.bob.sammy" value="123"/> </bean>
foo
ビーンには、bob
プロパティをもつfred
プロパティをもっていて、最下階層のsammy
プロパティにはスカラー値の123
が設定されている。これが有効に動作するために、foo
のfred
プロパティとfred
のbob
プロパティは、このビーンが生成された後、非ヌルでなければならない、さもないとnull-pointer Exception
が投げられる。
ユーザのほとんどにとって、コンテナにあるビーンの大部分はシングルトンだ。シングルトンビーンが他のシングルトンビーンとのコラボレートが必要になる場合、もしくは非シングルトンビーンが他の非シングルトンビーンとのコラボレートが必要になる場合、あるビーンを別のビーンのプロパティに定義することでこの依存関係を扱うという典型的なそして共通のアプローチは全く適切だ。 しかしながら、ビーンそれぞれのライフサイクルが違う場合、問題が発生する。あるシングルトンビーンAを考える。これはAにあるメソッドを起動するたびに非シングルトン(プロトタイプ)ビーンBを必要とする。コンテナはシングルトンビーンAを一度だけ生成し、プロパティへ設定を一度だけ行う機械を得る。でもコンテナがビーンAに、ビーンBが必要になるたびに新しいBのインスタンスを供給するような機会は得られないのだ。
この問題に対する1つの解は、inversion of controlをあきらめることだ。ビーンAはBeanFactoryAware
を実装することで、コンテナを意識することができ、(新しい)ビーンBが必要になるたびにgetBean("B")
を呼んでコンテナに問い合わせるというプログラミング的な方法を用いることができる。これはビーンのコードがSpringへのアクセスを意識することになるので一般的に望ましい解ではない。
BeanFactory
の高度な機能であるメソッドインジェクションであれば、他のシナリオと同様に、クリーンな方法でこのようなユースケースを扱うことが可能となる。
ルックアップメソッドインジェクションは、コンテナ内で管理されたビーンに対し、抽象メソッドもしくは具象メソッドを上書きするというコンテナの能力を用い、コンテナ内の他の名前のついたビーンをルックアップした結果を返す。このルックアップは典型的には、上述したシナリオ(これはシングルトンでもありうる)ごとに非シングルトンビーンのものだ。SpringではこれをCGLIBライブラリによるバイトコード生成を用いて、メソッドがオーバライドされたサブクラスを動的に生成することにより実装している。
インジェクションされるメソッドを含んでいるクライアントクラスでは、そのメソッドの定義は以下の形式でアブストラクト(あるいは具象)定義でなければならない。
protected abstract SingleShotHelper createSingleShotHelper();
そのメソッドがアブストラクトでなければ、Springは単純に既存の実装をオーバライドする。XmlBeanFactory
の場合、ビーン定義にあるlookup-method
要素を使ってSpringにこのメソッドに特定のビーンをコンテナから返すようにインジェクション/オーバライドするように指示する。例えばこんな風になるだろう。
<!-- a stateful bean deployed as a prototype (non-singleton) --> <bean id="singleShotHelper" class="..." singleton="false"> </bean> <!-- myBean uses singleShotHelper --> <bean id="myBean" class="..."> <lookup-method name="createSingleShotHelper" bean="singleShotHelper"/> <property> ... </property> </bean>
このmyBean
で指定されているビーンは、singleShotHelper
ビーンのインスタンスを必要とするときは必ずcreateSingleShotHelper
メソッドを呼ぶ。このビーンをデプロイする人は(それが実際に必要である場合に)singleShotHelper
を非シングルトンとして注意深くデプロイしなければならない点に注意することは重要だ。もしシングルトンとしてデプロイされた場合(明示的に、あるいはこのフラグのデフォルトのtrue
の値に頼って)、同じsingleShotHelper
のインスタンスが毎回返されてしまう。
ルックアップメソッドインジェクションはコンストラクタインジェクション(生成されたビーンにオプションのコンストラクタ引数を供給する)やセッターインジェクション(ビーンが生成される際にプロパティを設定する)とも組み合わせることができることに注意してほしい。
メソッドインジェクションの中で、ルックアップメソッドインジェクションほど一般的で有用ではない方法だが、管理下のビーンの任意のメソッドを別の実装に置き換える機能があるが、この機能が実際に必要となるまではこのセクションの以降(この多少高度な機能について述べている)を読み飛ばしてもらってもかまわない。
XmlBeanFactory
では、デプロイ済みのビーンに対し既存のメソッドの実装を他のものに置き換えるのにreplaced-method
要素を用いる。下記の、computeValue
メソッドをもつクラスをオーバライドすることを考えてみよう。
... public class MyValueCalculator { public String computeValue(String input) { ... some real code } ... some other methods }
org.springframework.beans.factory.support.MethodReplacer
インタフェースを実装するクラスには新しいメソッドの定義を用意する必要がある。
/** meant to be used to override the existing computeValue implementation in MyValueCalculator */ 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 ...; }
オリジナルクラスをデプロイするためのBeanFactory
デプロイ定義とメソッドのオーバライドの指定はこのようにして行う。
<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
個々の選択可能なものを区別するために引数の数が十分に多い場合があるので、この引数とマッチする短縮文字列を使うことで、タイピング量を減らすことができる。
ほとんどの状況では、あるビーンが他のビーンと依存関係にあるということは、つまり、あるビーンが他のビーンのプロパティに設定されていることで分かる。これは典型的にはXmlBeanFactory
にあるref
要素で示される。この方式では、時々コンテナを意識したビーンがその依存相手(文字列型の値、もしくはidref
要素が用いられる。これも文字列型の値と同じように評価される)のid
が与えられる。そして1つ目のビーンがプログラムによって自分の依存関係をコンテナに問い合わせる。いづれの場合においても、依存関係は依存するビーンよりも先に適切に初期化が行われる。
ビーン間の依存関係がそれほど直接的ではない(例えばデータベースドライバの登録のようにクラスの静的なイニシャライザが起動される必要がある)ような比較的まれな状況においては、depends-on
要素を使うビーンが初期化される前に明示的に1つ以上のビーンを初期化するためにdepends-on
要素を用いてもかまわない。
下記は、設定例だ。
<bean id="beanOne" class="ExampleBean" depends-on="manager"> <property name="manager"><ref local="manager"/></property> </bean> <bean id="manager" class="ManagerBean"/>
BeanFactory
は協調するビーンとの間で自動的に関連を持たせることができる。これは、BeanFactory
のコンテンツを認識することによって、自動的にSpringが協調相手(別のビーン)を解決するということだ。オートワイヤ機能には5つのモードが用意されている。オートワイヤは各ビーンごとに指定するので、あるビーンではオートワイヤが有効なのに、別のビーンではオートワイヤが無効といったことが可能だ。オートワイヤを使えば、指定しないといけないプロパティやコンストラクタ引数の数を減らす、さらにはなくすことができ、かなりのタイピングを減らすことができる(1)。XmlBeanFactory
の場合、ビーン定義のオートワイヤのモードはbean
要素のautowire
属性を使って指定する。この属性には以下のような値が設定可能だ。
モード | 説明 |
---|---|
autowireは全て無効。ビーンリファレンスはref 要素経由で定義されないといけない。これはデフォルト値であり、コラボレータを明示的に指定すると、制御しやすくまた明確になるので、より大規模なデプロイではこれを変更するのはお勧めしない。ある程度は、システムの構造についてのドキュメントの形をなしている。 |
|
byName | プロパティ名によるオートワイヤ。このオプションはBeanFactory を調べてオートワイヤされるべきプロパティと同じ名前のビーンを探す。例えば、名前によるオートワイヤが設定されているビーン定義があって、master プロパティを持っている(これは、つまりsetMaster(...) メソッドがあるということ)とすると、Springはmaster という名前のビーン定義を探しだし、プロパティの設定にこれを用いる。 |
byType | BeanFactory にそのプロパティの型のビーンが1つだけある場合に、そのプロパティがオートワイヤされる。もし複数のビーンがあれば、致命的な例外がスローされる。つまりこのようなビーンに対しては、byType のオートワイヤは使ってはいけないということだ。一致するビーンがなければ何も起きない。つまりプロパティはセットされない。これが望ましくないのであれば、この場合にエラーを発生させるようにdependency-check="object" の属性値を指定する。 |
constructor | これはbyType と似ているが、コンストラクタ引数に適用する。ビーンファクトリにコンストラクタ引数型のビーンが1個に限定できなければ致命的なエラーが発生する。 |
autodetect | ビーンクラスの中身によってconstructorかbyType かを選択する。デフォルトコンストラクタがあれば、byType が適用される。 |
property
要素やconstructor-arg
要素における明示的な依存関係は常にオートワイヤを上書きすることに注意してほしい。オートワイヤの振る舞いは依存性チェックと組み合わせることができ、これはオートワイヤ処理が完了した後で実行される。
オートワイヤに関する長所、短所を理解することは重要だ。オートワイヤリングの長所を以下に挙げる。
オートワイヤリングの短所としては以下のようなものがある。
いかなる場合においても、「これは間違っている」「これは正しい」ということは言えない。我々はプロジェクトを通じた一貫性をお勧めする。例えば、オートワイヤリングを通常利用していない場合、たったひとつ、あるいは二つのビーン定義をするためだけにオートワイヤリングを用いるのは開発者を混乱させることになるだろう。
Springでは、BeanFactory
にデプロイされたビーンの名前解決されていない依存関係が存在するかをチェックさせることができる。これは、ビーンのJavaBeansプロパティであって、これは、実際の値がビーン定義中に設定されていないかもしくは自動的にオートワイヤ機能によって設定されたものだ。
全てのプロパティ(もしくは特定の型のプロパティ全部)が設定されることを保証したい場合、この機能が役に立つことがある。もちろん、多くの場合、ビーンクラスはその多くのプロパティにはデフォルト値があり、中には想定シナリオ全部で適用するわけではないプロパティもあるので、この機能は限定的に利用される。依存関係チェックも、オートワイヤ機能と同じようにビーンごとに有効/無効を指定することができる。デフォルトでは依存関係チェックを行わない。依存関係チェックは異なるモードでの動作が可能だ。XmlBeanFactory
では、ビーン定義にあるdependency-check
属性で指定され、この属性には下記のような値が設定される。
no | 依存関係チェックを行わない。指定された値を持たないプロパティは単に設定されないだけ。 |
simple | プリミティブ型とコレクション(コラボレータ、つまり別のビーンを除く全て)に対して依存関係チェックを実行する。 |
object | コラボレータに対して依存関係チェックを実施する。 |
all | コラボレータ、プリミティブ型、コレクションに対して依存関係チェックを実施する。 |
SpringではBeanFactory
中でビーンの振る舞いを変更するためにマーカーインタフェースがいくつか提供されている。これにはInitializingBean
やDisposableBean
も含まれている。このインタフェースを実装すると、初期化やデストラクタで何か処理ができるようにBeanFactory
で前者にはafterPropertiesSet()
が呼ばれ、後者にはdestroy()
が呼ばれ、ビーンの初期化、あるいは削除の際にアクションを実行させることができるようになる。
内部的には、Springは任意のマーカーインタフェースが適切なメソッドを見つけて実行するようにBeanPostProcessors
を使う。もし機能のカスタマイズをしたりSpringがかなわない他の優れたライフサイクル動作が必要であれば、BeanPostProcessor
を自分で実装すればよい。これに関する詳細は章[3.7 BeanPostProcessorsを使ってBeanFactoryをカスタマイズする]にある。
異なるライフサイクルマーカーインタフェースは全て下記に示してある。付録の中に、Springがビーンをどのように管理するか、ライフサイクル機能がどのようにビーンの性質を変更するか、またそれらがどのように管理されるかを示すダイアグラムがある
org.springframework.beans.factory.InitializingBean
を実装すると、BeanFactory
が必要なプロパティを全て設定した後にビーンに初期化を実行させることができるようになる。InitializingBean
インタフェースにはメソッドが1つだけ指定されている。
* Invoked by a BeanFactory after it has set all bean properties supplied * (and satisfied BeanFactoryAware and ApplicationContextAware). * <p>This method allows the bean instance to perform initialization only * possible when all bean properties have been set and to throw an * exception in the event of misconfiguration. * @throws Exception in the event of misconfiguration (such * as failure to set an essential property) or if initialization fails. */ void afterPropertiesSet() throws Exception;
注意:一般に、InitializingBean
マーカーインタフェースは使わないで済ませることができる(Springとの不必要な結合性を作るので使うことをよしとしない)。ビーン定義は指定された汎用的な初期化メソッドのサポートを提供する。XmlBeanFactory
の場合には、これはinit-method
属性により実行される。例えば下記のような定義があるとしよう。
<bean id="exampleInitBean" class="examples.ExampleBean" \ init-method="init"/> public class ExampleBean { public void init() { // do some initialization work } }
<bean id="exampleInitBean" class="examples.ExampleBean" \ init-method="init"/>
これは、厳密に以下と同じだ。
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean { public void afterPropertiesSet() { // do some initialization work } }
しかし、Springと密接に結合はしていないのである。
org.springframework.beans.factory.DisposableBean
インタフェースを実装すると、そのビーンが含まれているBeanFactory
がデストロイされたときにビーンがコールバックを受け取ることができるようになる。このDisposableBean
インタフェースにはメソッドが1つ指定されている。
/** * Invoked by a BeanFactory on destruction of a singleton. * @throws Exception in case of shutdown errors. * Exceptions will get logged but not rethrown to allow * other beans to release their resources too. */ void destroy() throws Exception;
注:一般に、DisposableBean
マーカーインターフェースを使わずに済む手がある(がコードがSpringと不必要に密接になるのであまりお勧めできない)。ビーン定義では汎用のデストロイメソッドの指定がサポートされている。XmlBeanFactory
の場合、これはdestory-method
属性で指定される。例えば下記のような定義があるとしよう。
<bean id="exampleInitBean" class="examples.ExampleBean" \ destroy-method="cleanup"/>
public class ExampleBean { public void cleanup() { // do some destruction work (like closing connection) } }
これは、厳密に以下と同じだ。
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean { public void destroy() { // do some destruction work } }
しかし、Springとコードが密接に結合しないのである。
重要な注意: プロトタイプモードでビーンをデプロイする場合、そのビーンのライフサイクルは少し変わる。定義により、Springでは非シングルトン/プロトタイプビーンの完全なライフサイクルを管理することはできない。というのは、生成後、もはや全く把握していないクライアントやコンテナに渡されるからだ。非シングルトン/プロトタイプビーンをnew
オペレータの代わりとして話すときのSpringの役割について考えることができる。そのポイントを過ぎたアスペクトはなんでもクライアントにより扱われなければならないのだ。BeanFactory
におけるビーンのライフサイクルについてのより詳細は、3.4.1章 "ライフサイクルインタフェース"で述べられている。
org.springframework.beans.factory.BeanFactoryAware
インタフェースを実装したクラスはそれを生成したBeanFactory
へのリファレンスをもっており、それはBeanFactory
によって生成されたときに渡される。
public interface BeanFactoryAware { /** * Callback that supplies the owning factory to a bean instance. * <p>Invoked after population of normal bean properties but before an init * callback like InitializingBean's afterPropertiesSet or a custom init-method. * @param beanFactory owning BeanFactory (may not be null). * The bean can immediately call methods on the factory. * @throws BeansException in case of initialization errors * @see BeanInitializationException */ void setBeanFactory(BeanFactory beanFactory) throws BeansException; }
これにより、org.springframework.beans.factory.BeanFactory
インタフェースによって、あるいは付加機能を公開する既知のサブクラスへのリファレンスへキャストすることによって、ビーンから、そのビーンをプログラム的に生成したBeanFactory
を操作することができるようになる。まず、これはプログラミングによって他のビーンの検索から構成される。この機能が有効な場合、Springとコードが密接になってしまい、コラボレータがプロパティとしてビーンに設定されるのでInversion of Controlスタイルに従わなくなり、ので一般的には避けるべきである。
org.springframework.beans.factory.BeanNameAware
インタフェースを実装するビーンがあって、それが、BeanFactory
中にデプロイされている場合、そのBeanFactory
はそのビーンをこのインタフェース経由で呼び出し、デプロイ下にいるという印にそのビーンのIDを設定する。このコールバックは、InitializingBean
のafterPropertiesSet
もしくは独自のinit-method
のように通常のビーンプロパティが構成された後、コールバックが初期化される前に起動される。
void setBeanName(String)
:ビーンに名前が何かを知らしめるために呼ばれるメソッドorg.springframework.beans.factory.FactoryBean
インタフェースは、BeanFactory
インタフェースには3つのメソッドが用意されている。
Object getObject()
:はこのファクトリが生成したオブジェクトのインスタンスを返さないといけない。そのインスタンスはおそらく共有されている(そのファクトリがシングルトンを返すのかプロトタイプを返すのかに依存する)
boolean isSingleton()
:はそのFactoryBean
シングルトンを返せばtrue
を返し、そうでなければfalse
を返す
Class getObjectType()
:はgetObject()
メソッドによって返されたオブジェクト型か、その型が前もって知らない場合はnull
を返さないといけないビーン定義には、大量の設定情報が含まれており、これにはコンテナに依存した情報(つまり、初期化メソッド、静的なファクトリメソッド名など)やコンストラクタ引数、プロパティ値も含まれる。チャイルドビーン定義というのは設定データを親の定義から継承したビーン定義であり、その際値をオーバライドしたり、必要に応じて値を追加といったことが可能である。親子ビーン定義を使うことにより、型が増えるのを抑えることができる。実際には、これはテンプレートの形式だ。
BeanFactory
をプログラム的に使う場合、チャイルドビーン定義はChildBeanDefinition
クラスによってあらわされる。ほとんどのユーザにとっては、このレベルの処理をする必要はなく、代わりにXmlBeanFactory
のような設定ビーン定義を宣言的に用いる。XmlBeanFactory
ビーン定義では、チャイルドビーン定義は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"/> <!-- age should inherit value of 1 from parent --> </bean>
チャイルドビーンの定義が指定されていなければ親の定義で用いられるビーンクラスを用いるが、オーバライドすることも可能だ。後者の場合、チャイルドビーンクラスは親クラスと互換性を持たなければならない。つまり、親のプロパティの値が設定可能である必要がある。
チャイルドビーン定義は、コンストラクタ引数の値、プロパティの値、メソッドのオーバライドを親から継承し、さらに新しい値を追加する。初期化メソッド、デストロイメソッド、そして/あるいは静的なファクトリメソッドが指定されていれば対応する親の設定をオーバライドする。
依存関係、オートワイヤモード、依存性チェック、シングルトン、遅延初期化等の残りの設定は通常、子供の定義から取得される。
上記の例では、親のビーン定義に、abstractというふうに、abstract属性を使って明示的にマーキングを行った。下記では、親の定義はクラスを指定していない
<bean id="inheritedTestBeanWithoutClass"> <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 should inherit value of 1 from parent --> </bean>
この親ビーン自身不完全であり、アブストラクトなのでなのでインスタンス化することはできない。このように定義がアブストラクトとされている場合(明示的にであろうと暗黙的にであろうと)、純粋なテンプレートもしくは、子定義に対し親として提供するアブストラクトビーン定義として使うことができる。(他のビーンのref
プロパティで参照することによって)そのようなアブストラクト親ビーンを使おうとしたり、あるいは明示的に親ビーンIDを指定してgetBean()
を呼んでもエラーになってしまう。同様に、コンテナ内部のpreInstantiateSingletons
メソッドはアブストラクトのビーン定義は完全に無視する。
重要:アプリケーションコンテキスト(単純なビーンファクトリではなく)はデフォルトで全てのシングルトンをあらかじめインスタンス生成を行う。従って、(少なくともシングルトンビーンでは)、テンプレートとしてしか使うつもりのないビーン定義があって、その定義にクラスが指定してあると、abstract
属性をtrue
に設定しないといけない。さもないと、アプリケーションコンテキストは実際にインスタンス生成を実行してしまう。
BeanFactory
は本質的にには、異なるビーンの登録とそれらの依存関係の管理ができる高機能なファクトリのためのインタフェースに過ぎない。このBeanFactory
では、ビーン定義を読み込んでビーンファクトリ経由でアクセスすることができる。BeanFactory
であれば、下記のようなXMLフォーマットのビーン定義を読み込んでビーンを生成することができる。
InputStream is = new FileInputStream("beans.xml"); XmlBeanFactory factory = new XmlBeanFactory(is);
基本的には全部用意されている。getBean(String)
を使って自分のビーンのインスタンスを検索することができる。もしそれをシングルトン(これがデフォルト)として定義してあれば、同じビーンへの参照を取得したり、シングルトンにfalse
が設定してあれば毎回新しいインスタンスを取得できる。クライアント側のBeanFactory
の見え方は驚くほど単純だ。BeanFactory
インタフェースにはクライアントが呼ぶためのメソッドは5つしか用意されていない。
boolean containsBean(String)
: BeanFactory
に渡された名前に一致するビーン定義もしくはビーンインスタンスがあればtrue
を返す
Object getBean(String)
:渡された名前で登録されているビーンのインスタンスを返す。シングルトンな共有インスタンスが返されるかあるいは新しく生成されたビーンが返されるかはBeanFactory
設定によってそのビーンがどう設定されているかによる。BeanException
が投げられるのはそのビーンが見つからなかった場合(この場合は、NoSuchBeanDefinitionException
)か、あるいはビーンをインスタンス化し準備する最中に例外が発生したかどちらかの場合である。
Object getBean(String,Class)
:渡された名前で登録されたビーンを返す。返されるビーンは渡されたクラスにキャストされる。そのビーンがキャストできない場合は、対応する例外が投げられる(BeanNotOfRegisteredTypeException
)。さらに、getBean(String)
メソッドのルールが全て適用される(上述を参照)。
boolean isSingleton(String)
:渡された名前で登録されたビーン定義もしくはビーンインスタンスがシングルトンかプロトタイプかを判断する。渡された名前に対応するビーンが見つからない場合、例外が投げられる(NoSuchBeanDefinitionException
)。
String[] getAlias(String)
: BeanDefinition
に他に定義されていれば渡されたビーン名のエイリアスを返す時には、BeanFactory
が生成したビーンではなく、BeanFactory
インスタンスそのものをBeanFactory
に対して問い合わせる必要が生じることがある。これは BeanFactory
のgetBean
メソッドを呼んだとき(ApplicationContext
の場合も含む)にビーンIDの頭に&をつけることで行われる。したがって、myBean
というIDがついているFactoryBean
の場合は、BeanFactory
のgetBean("myBean")
を実行するとそのFactoryBean
が生成したものが返されるが、getBean("&myBean")
を実行するとFactoryBean
のインスタンスそのものが返される。
ビーンポストプロセッサは、org.springframework.beans.factory.config.BeanPostProcessor
インタフェースを実装したjavaクラスであり、2つのコールバックメソッドで構成される。このクラスがpost-processor
としてBeanFactory
に登録されると、そのBeanFactory
で生成された各ビーンインスタンスに対し、そのポストプロセッサは初期化メソッド(afterPropertiesSet
や何か宣言されている初期化メソッド)が呼ばれる前、さらに呼ばれた後にBeanFactory
からコールバックを得る。このpost-processor
は、コールバックを完全に無視するのも含めてビーンに対して実行したいことであれば何でも可能だ。典型的なビーンポストプロセッサでは、マーカインタフェースをチェックするか、あるいはビーンをプロキシでラップしたりする。Springのヘルパークラスにはビーンポストプロセッサとして実装されているものもある。
BeanFactory
のビーンポストプロセッサに対する扱うはApplicationContext
とはわずかに異なるということを知っておくことは重要だ。ApplicationContext
はBeanPostProcessor
インタフェースが実装されたビーンがデプロイされるのを自動的に認識し、ビーン生成時にファクトリから適切に呼ばれるようにそれをpost-processor
として登録する。ポストプロセッサは他のビーンと同じやり方でデプロイする以外には何もする必要はないのだ。一方、素のBeanFactory
を使う場合、ビーンポストプロセッサは下記のようなコードを使って明示的に手動で登録しなければならないのだ。
ConfigurableBeanFactory bf = new .....; // create BeanFactory ... // now register some beans // now register any needed BeanPostProcessors MyBeanPostProcessor pp = new MyBeanPostProcessor(); bf.addBeanPostProcessor(pp); // now start using the factory ...
本マニュアルの登録手順は不便であり、ApplicationContext
は機能的にはBeanFactory
のスーパーセットなので、ApplicationContext
の派生はポストプロセッサを必要とする場合に使用するのをお勧めする。
ビーンファクトリポストプロセッサはorg.springframework.beans.factory.config.BeanFactoryPostProcessor
インタフェースを実装したJavaクラスである。コンストラクタ実行後、BeanFactory
全体へのなんらかの変更が(BeanFactory
の場合には)マニュアルで、(ApplicationContext
の場合には)自動で実行される。Springには先に述べたPropertyResourceConfigurer
やPropertyPlaceHolderConfigurer
のような生成前ビーンファクトリポストプロセッサが多く含まれており、本マニュアルで後述しているようにBeanNameAutoProxyCreator
は他のビーンや、他の種類のプロキシでラップするのに役に立つ。BeanFactoryPostProcessor
は(章[3.9 カスタマイズしたPropertyEditorsを追加で登録する]で述べているように)カスタムエディタを追加するのに用いることができる。
BeanFactory
では、BeanFactoryPostProcessor
を適用する手順は手動であり、下記と似たようなものである。
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml")); // create placeholderconfigurer to bring in some property // values from a Properties file PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); cfg.setLocation(new FileSystemResource("jdbc.properties")); // now actually do the replacement cfg.postProcessBeanFactory(factory);
ApplicationContext
はBeanFactoryPostProcessor
インタフェースを実装したビーンがアプリケーションコンテキスト内にデプロイされるのを検出し、適切なタイミングで自動的にビーンファクトリポストプロセッサとして利用する。このポストプロセッサをデプロイするには他のビーンと同じやり方でデプロイする以外には何も必要ない。
本マニュアルの手順は不便だし、ApplicationContext
は機能的にBeanFactory
のスーパーセットなので、一般的には、ビーンファクトリポストプロセッサを必要とする場合はApplicationContext
の派生を用いることをお勧めする。
ビーンファクトリポストプロセッサとして実装されたPropertyPlaceholderConfigurer
はプロパティ値をBeanFactory
定義を外に出してJavaプロパティのフォーマットで書かれた別のファイルに取り込むのに用いる。これは、メインのXML定義ファイルやBeanFactory
のファイルを編集するという複雑でリスクなことをせずに、ユーザにプロパティをいくつかいじってデプロイできるようにする(例えば、データベースのURL,ユーザ名、パスワード)のに便利だ。
placeholder
の値をもつデータソースが定義されているBeanFactory
定義の断片を見てみよう。
下記の例にあるように、データソースが定義されており、外部プロパティファイルからあるプロパティ値を設定する。実行時に、データソースのプロパティを書き換えるBeanFactory
にPropertyPlaceholderConfigurer
を適用する。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" \ destroy-method="close"> <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>
この実際の値については、Properties
形式の別のファイルから取得する
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
これをBeanFactory
と一緒に使うために、ビーンファクトリポストプロセッサを手動で実行する。
XmlBeanFactory factory = new XmlBeanFactory(new \ FileSystemResource("beans.xml")); PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); cfg.setLocation(new FileSystemResource("jdbc.properties")); cfg.postProcessBeanFactory(factory);
ApplicationContext
では、BeanFactoryPostProcessor
を実装したビーンがデプロイされたらそれを自動的に認識して適用することが可能であることに注意して欲しい。これはつまり、ここで記述されているように、ApplicationContext
を使う場合はPropertyPlaceholderConfigurer
を適用する方がもっと便利だ、ということだ。PropertyPlaceholderConfiguer
やあるいはその他のビーンファクトリポストプロセッサを使う場合は、BeanFactory
よりもApplicationContext
を使うほうをお勧めする。
このPropertyPlaceholderConfigurer
は指定したProperties
のファイルにあるプロパティを探すだけでなく、使おうとするプロパティが見つからない場合にJavaのシステムプロパティへのチェックも行う。この振る舞いはconfigurer
のsystemPropertiesMode
というプロパティを設定することでカスタマイズが可能だ。このプロパティには3通りの値があり、1つは常にオーバライドする、1つはオーバライド禁止、そしてもうひとつは、プロパティが指定されたプロパティファイルに見つからない場合のみオーバライドするというものだ。より詳細な情報は、PropertiesPlaceholderConfigurer
のJavaDocを参照して欲しい。
別のビーンファクトリポストプロセッサであるPropertyOverrideConfigurer
はPropertyPlaceholderConfigurer
と似ているが、後者と違う点は、元の定義にあるビーンプロパティ全てにデフォルト値が用意されているかいないかである。オーバライドしたProperties
ファイルにあるビーンプロパティのエントリがなかったら、デフォルトのコンテキスト定義が使われる。
ビーンファクトリの定義はそれがオーバライドされるかどうかは関知しない、という点に注意してほしい。よって、オーバライドconfigurer
を用いているXML定義ファイルを見てもすぐにはわからないと思う。PropertyOverrideConfigurers
が複数異なる値で同じビーンプロパティに定義されている場合、(オーバライドのメカニズムにより)一番最後の設定が有効となる。
Properties
ファイルの設定行は、下記のような形式で記述されていることが求められる。
beanName.property=value
プロパティファイルの例はこのようなものだ。
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
この例で挙げたファイルは、driver
やurl
といったプロパティを持つdataSource
と呼ばれるビーンを持つBeanFactory
の定義に用いることができる。
オーバライドされてすでに非ヌルである(おそらくコンストラクタで初期化された)ファイナルプロパティを除くすべてのコンポネントと同様、複合プロパティ名もサポートされている点に注意してほしい。下記の例:
foo.fred.bob.sammy=123
では、foo
ビーンのfred
プロパティのbob
プロパティのsammy
プロパティがスカラー値123
に設定されている。
ビーンプロパティを文字列値として設定する場合、その文字列をプロパティの複雑な型に変換するために、BeanFactory
は最終的に標準のJavaBeans PropertyEditors
を使う。Springではあらかじめ多くの独自PropertyEditors
(例えば、文字列で表現されたクラス名を実際のClass
オブジェクトに変換するため)を登録する。さらに、Java標準のJavaBeans PropertyEditor
のルックアップメカニズムでは、PropertyEditor
が適当な名前がつけられ、サポートすべきクラスと同じパッケージに配置されるように自動的に見つけられる。
他にもカスタマイズしたPropertyEditor
を登録する必要がある場合は、いくつかの方法を使うことができる。
一番手間のかかる方法(通常は不便でお勧めしない)は、BeanFactory
へのリファレンスがあると仮定して、ConfigurableBeanFactory
インタフェースのregisterCustomEditor()
メソッドを使うだけだ。
これよりも便利な方法は、CustomEditorConfigurer
と呼ばれる特別なビーンファクトリポストプロセッサを使うというものだ。ビーンファクトリポストプロセッサはBeanFactory
とともに半手動で使うことができるが、これはネストされたプロパティ設定を持っているので、ここで述べたように、他のビーンと同じようにデプロイして自動的に検出、適用されるApplicationContext
と一緒に使うことを強くお勧めする。
全てのビーンファクトリやアプリケーションコンテキストはプロパティ変換を行うBeanWrapper
と呼ばれるものを使って、多くの組み込みプロパティエディタを利用するという点に注意してほしい。BeanWrapper
が登録する標準のプロパティエディタは次章に列記してある。さらに、ApplicationContext
も特定のアプリケーションのコンテキストのタイプに応じてリソースのルックアップを行うために3つのエディタをオーバライド、もしくは追加を行う。その3つとは、InputStreamEditor
,ResourceEditor
,URLEditor
である。
あるビーン定義の中で、id
属性を使って1つの名前を指定し、alias
属性を使って他の名前を使う、という組み合わせによりそのビーンに複数の名前をつけることは可能だ。この名前はすべて同じビーンの等価な別名とみなされ、あるアプリケーションで用いられている各コンポネントがそのコンポネント自身をさすビーン名を使って共通の依存性を参照するような状況においては便利である。
しかしながら、そのビーンが実際に定義されている場合にすべての別名を指名しなければならないのは必ずしも適当ではない。他の場所で定義されているビーンに別名を導入するのは望ましいこともあるが、これは、スタンドアロンなalias
要素を使って指定されることもある。
<alias name="fromName" alias="toName"/>
この場合、fromName
という名前の同じコンテキストのビーンがこのalias
定義を利用することでtoName
で参照される。
具体的な例として、コンポネントAがそのXML定義ファイルの中でcomponentA-dataSource
というDataSource
ビーンを定義する場合を考えてみる。しかしながらコンポネントBがそのXML定義ファイルの中でそのDataSource
をcomponentB-dataSource
として参照したい。また、メインのアプリケーションMyApp
がそのXML定義ファイルの中でこれらのXMLファイルから最終的にアプリケーションコンテキストを定義構築し、そのDataSource
をmyApp-dataSource
という名前で参照したい。このシナリオは、MyApp
のXMLファイルに下記のスタンドアロンエイリアスを追加することで簡単に扱うことができる。
<alias name="componentA-dataSource" alias="componentB-dataSource"/> <alias name="componentA-dataSource" alias="myApp-dataSource"/>
ここで、各コンポネントとメインのapp
は一意で他の定義とぶつからないことが保障された(名前空間という便利なものがある)、でも同じビーンを参照する名前を使って、dataSource
を参照することができる。
ビーンパッケージでは、ビーンを維持管理するための基本的な機能が用意されているが、しばしばプログラム的なやり方で、コンテキストパッケージがBeanFactory
をもっとフレームワーク指向な方法で機能を拡張するApplicationContext
を追加する。多くのユーザはApplicationContext
を完全に宣言的なやり方で、手動で生成する必要がなく、その代わりJ2EEウェブアプリの通常の起動手順の一部としてApplicationContext
を自動的に起動するためのContextLoader
のようなサポートクラスに依存して利用する。もちろん、プログラム的にApplicationContext
を生成することも可能だ。
コンテキストパッケージの基礎となるのはorg.springframework.context
パッケージに配置されているApplicationContext
インタフェースだ。BeanFactory
インタフェースにより、BeanFactory
の全機能を提供する。レイヤリングや階層コンテキストを使ってよりフレームワーク指向なやり方で使うために、コンテキストパッケージでは下記の機能も提供されている。
MessageSource
ApplicationListener
インタフェースを実装したビーンへのイベントの伝播
ApplicationContext
がBeanFactory
の全機能を含んでいるように、通常は、おそらくアプレットのようにメモリの消費がクリティカルで、余計な数百キロバイトで違いが生じる状況のようないくつかの制限のある状況を除いて、BeanFactory
上で用いられることが一般的に推奨される。次のセクションでは、ApplicationContext
が基本的なBeanFactory
でできることに追加する機能について述べてある。
前のセクションで既に述べたように、ApplicationContext
にはBeanFactory
とは異なる機能が2,3用意されている。それを1つ1つ見ていくことにしよう。
ApplicationContext
インタフェースはMessageSource
と呼ばれるインタフェースを拡張したものなので、(i18nもしくは国際化)メッセージング機能を持つ。階層化されたメッセージを解決することができるNestingMessageSource
とともに、Springが提供するメッセージ解決を行う基本インタフェースである。このインタフェースに定義されているメソッドを見ていくことにしよう。
String getMEssage(String code, Object[] args, String default, Locale loc)
:MessageSource
からのメッセージを検索するための基本メソッド。指定したロケールのメッセージが見つからなかった場合、default
で指定されたメッセージが使われる。ここで渡される引数は、標準ライブラリで提供されているMessageFormat
機能を使って書き換える値として利用される。
String getMessage (String code, Object[] args, Locale loc)
:本質的に、上記メソッドと同じだが1点だけ、メッセージが見つからなかった場合、default
メッセージを指定することができないので、NoSuchMessageException
をスローする点が異なる。
String getMessage(MessageSourceResolvable resolvable, Locale locale)
:上記のメソッドで使われているプロパティは全てMessageSourceResolvable
という名前の1つのクラスにラップされている。このクラスはこのメソッドから利用が可能。ApplicationContext
がロードされるとき、自動的にそのコンテキストで定義されているMessageSource
ビーンを探しにいく。このビーンはname
というmessageSource
を持っている必要がある。もし、そのようなビーンが見つかれば、上記で説明したメソッドの呼び出しは全て見つかったメッセージソースに委譲される。もしメッセージソースが見つからなかった場合、ApplicationContext
は親が同様の名前を持ったビーンを持っているとみなす。もし持っていれば、そのビーンをMessageSource
として利用する。もしメッセージソースが見つからなかった場合、上記で定義されたメソッドが呼ばれてもいいように、空のStaticMessageSource
がインスタンス化される。
Springでは現在、2種類のMessageSource
の実装が提供されている。その2つとはResourceBundleMEssageSource
とStaticMessageSource
だ。共に、ネストされたメッセージを処理するためにNestingMessageSource
を実装している。StaticMessageSource
はもうほとんど使われないが、メッセージをソースに追加するのにプログラム的な方法を提供する。ResourceBundleMessageSource
はさらに興味深いものなので、以下に例を示す。
<beans> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>format</value> <value>exceptions</value> <value>windows</value> </list> </property> </bean> </beans>
ここでは、format、例外、そしてウィンドウと呼ばれるクラスパスに定義されている2つのリソースバンドルがあると仮定している。JDKのメッセージをResourceBundles
に解決する標準的な方法を使って、メッセージを解決する要求がバンドルされる。TODO:SHOW AN EXAMPLE
ApplicationContext
におけるイベントハンドリングはApplicationEvent
クラスとApplicationListener
インタフェースで提供されている。ApplicationListener
インタフェースが実装されたビーンがそのコンテキストにデプロイされると、ApplicationEvent
がApplicationcontext
に対して毎回発行される度にそのビーンにそれが通知される。これは標準的なオブザーバデザインパターンだ。Springでは標準のイベントが3つ用意されている。
イベント | 説明 |
---|---|
ContextRefreshedEvent |
ApplicationContext が初期化、もしくはリフレッシュされたときに発行されるイベント。ここでいう初期化とは全てのビーンがロードされ、シングルトンはあらかじめインスタンス化され、ApplicationContext が使えるように準備が整ったということだ。 |
ConetxtClosedEvent |
ApplicationContext が、ApplicationContext に定義されているclose() メソッドを使ってクローズされたときに発行されるイベント。ここでいうクローズとは、シングルトンがデストロイされたということである。 |
RequestHandlerEvent |
HTTPリクエストを受けつける全てのビーンが喋るWebに特化したイベント(つまり、リクエストが完了したら発行されるものだ)。このイベントは、SpringのDispatcherServlet を使ったウェブアプリケーションでのみ当てはまる、という点にご注意を。) |
独自のイベントを実装することももちろん可能だ。単に、ApplicationEvent
を実装した独自のイベントクラスのインスタンスをパラメータに指定してApplicationContext
のpublishEvent()
メソッドを叩くだけだ。イベントリスナは同期的にイベントを受信する。これはpublishEvent()
メソッドが、すべてのリスナーがイベント処理を完了するまでブロックするということだ。さらに言うと、あるリスナがイベントを受信したとき、もしトランザクションコンテキストが有効であれば、これは送信側のトランザクションコンテキストの内部で処理が行われる。
例を見てみよう。まずはApplicationContext
だ。
<bean id="emailer" class="example.EmailBean"> <property name="blackList"> <list> <value>black@list.org</value> <value>white@list.org</value> <value>john@doe.org</value> </list> </property> </bean> <bean id="blackListListener" class="example.BlackListNotifier"> <property name="notificationAddress" value="spam@list.org"/> </bean>
次は、実際のビーンだ。
public class EmailBean implements ApplicationContextAware { /** the blacklist */ private List blackList; public void setBlackList(List blackList) { this.blackList = blackList; } public void setApplicationContext(ApplicationContext ctx) { this.ctx = ctx; } public void sendEmail(String address, String text) { if (blackList.contains(address)) { BlackListEvent evt = new BlackListEvent(address, text); ctx.publishEvent(evt); return; } // send email } } public class BlackListNotifier implement ApplicationListener { /** notification address */ private String notificationAddress; public void setNotificationAddress(String notificationAddress) { this.notificationAddress = notificationAddress; } public void onApplicationEvent(ApplicationEvent evt) { if (evt instanceof BlackListEvent) { // notify appropriate person } } }
Of course, this particular example could probably be implemented in better ways (perhaps by using AOP features), but it should be sufficient to illustrate the basic event mechanism.
もちろん、この例については、おそらくもっといい方法で実装することは可能だろう(AOP機能を使えば)。だが、基本的なイベントの仕組みについて示すにはこれで十分のはずだ。
アプリケーションコンテキストを使いこなし、理解するには、4章「低レベルのリソースへのアクセスを抽象化する」に記述されているように、Springのリソース抽象化に習熟すべきだ。
アプリケーションコンテキストは、ResourceLoader
で、Resources
をロードするのに利用することができる。Resource
は、本質的には、java.net.URL
であり(実際、適切なURLを使ってラップする)、クラスパスから、ファイルシステム中の位置、標準URLで記述可能な場所やその他さまざまな場所を含め、任意の場所から透過的な方法で低レベルリソースを取得するのに用いることができる。もし、そのリソースの位置をあらわす文字列が特別なプレフィックスがついていない単純なパスであれば、その資源の位置は実際のアプリケーションコンテキストの型に応じて適切に指定される。
アプリケーションコンテキストにデプロイされたビーンは初期化時にResourceLoader
として解析されたアプリケーションコンテキストから自動的にコールバックされるように特別なmarker
インタフェース、ResourceLoaderAware
を実装する。
ビーンは、さらにResource
型のプロパティを外部に公開する。これはスタティックなリソースへアクセスするのに用いられ、また他のプロパティのように注入されることを期待する。このビーンをデプロイする人は、そのResource
プロパティに単純な文字列パスを指定する。そしてそのテキスト文字列を実際のResource
オブジェクトに変換するために、自動的にコンテキストによって登録された特別なJavaBean PropertyEditor
をあてにするかもしれない。
ロケーションパスやApplicationContext
のコンストラクタで提供されるパスは実際にはリソース文字列であり、これらは単純な形式で特定のコンテキストの実装として適切に扱われる(つまり、ClassPathXmlApplicationContext
は単純なロケーションパスをクラスパスロケーションとして扱う)が、さらに特別なプレフィクスとともに、実際のコンテキスト型に関わらずクラスパスやURLから定義を強制的にロードするのに用いられることもある。
前述した章ではこれらの話題についてさらに詳しく述べられている。
BeanFactory
にはすでに(XmlBeanFactory config
にあるinit-method
やdestroy-method
属性やビーンポストプロセッサのような評価しか設定で行わないInitializingBean
やDisposableBean
のようなマーカーインタフェースのように)デプロイされたビーンのライフサイクルを制御するための機構が多くされている。ApplicationContext
ではこの全部が動作するが、さらにビーンやコンテナの振る舞いをカスタマイズするメカニズムが追加されている。
BeanFactory
で利用可能なマーカーインタフェースは全てまだ動作する。ApplicationContext
は、org.springframework.context.ApplicationContextAware
を実装する特別なマーカーインタフェースを追加する。このインタフェースを実装し、コンテキストへデプロイされたビーンは、このインタフェースのsetApplicationContext()
メソッドを使ってビーン生成時にコールバックされ、コンテキストへのリファレンスを受け取り、以降、コンテキストとのインタラクション用に格納される。
org.springframework.beans.factory.config.BeanPostProcessor
インタフェースを実装したjavaクラスであるビーンポストプロセッサについてはすでに述べたが、ポストプロセッサは、素のBeanFactory
で使うよりもApplicationContext
で使った方がとても便利で、再度取り上げるだけの価値はあるだろう。ApplicationContext
では上述のマーカーインタフェースを実装したビーンをデプロイすると、ファクトリ内部で生成させるたびに適切に呼び出されるように自動的に検出されビーンポストプロセッサとして登録される。
org.springframework.beans.factory.config.BeanFactoryPostProcessor
インタフェースを実装したJavaクラスであるビーンファクトリポストプロセッサについてはすでに述べたが、ビーンファクトリポストプロセッサをApplicationContext
で使うのは素のBeanFactory
よりもとても便利なので再度取り上げるだけの価値はあるだろう。ApplicationContext
では、上述したマーカーインタフェースが実装されたビーンがデプロイされると適切なときに呼び出されるように自動的にビーンファクトリポストプロセッサとして検出される。
PropertyPlaceholderConfigurer
はBeanFactory
と一緒に使う旨すでに述べたが、ApplicationContext
で利用するとより便利なのでここで取り上げる価値があると思う。というのは、コンテキストは、他のビーンと同じようにデプロイされるだけで自動的にこのようなビーンファクトリポストプロセッサを認識し適用することができるからである。これを実行するのに、特別な手動操作をなんら必要としない。
<!- property placeholder post-processor -> <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> value="dbc.properties"/> </bean>
前述したように、標準のJavaBeansのPropertyEditor
は文字列で表現されているプロパティの値を実際のプロパティの複雑な型に変換するのに用いられる。CustomEditorConfigurer
というビーンファクトリポストプロセッサはApplicationContext
に追加のPropertyEditor
をサポートできるように便利に使うことができる。
ExoticType
というユーザクラスと、プロパティとしてExoticType
のセットを必要とする別のクラスDependsOnExoticType
を考えてみよう。
public class ExoticType { private String name; public ExoticType(String name) { this.name = name; } } public class DependsOnExoticType { private ExoticType type; public void setType(ExoticType type) { this.type = type; } }
これらが適切にセットアップされると、この型プロパティに文字列で割り当てて、背後で実際のExoticType
オブジェクトに変換されるのを望む。
<bean id="sample" class="example.DependsOnExoticType"> <property name="type"><value>aNameForExoticType</value></property> </bean>
このPropertyEditor
は下記に似ているように見ることができる。
// converts string representation to ExoticType object public class ExoticTypeEditor extends PropertyEditorSupport { private String format; public void setFormat(String format) { this.format = format; } public void setAsText(String text) { if (format != null && format.equals("upperCase")) { text = text.toUpperCase(); } ExoticType type = new ExoticType(text); setValue(type); } }
最後に、新しいPropertyEditor
をApplicationContext
に登録するのにCustomEditorConfigurer
を使う。これで、必要に応じて使うことができるようになる。
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="example.ExoticType"> <bean class="example.ExoticTypeEditor"> <property name="format" value="upperCase" /> </bean> </entry> </map> </property> </bean>
PropertyPathFactoryBean
は与えられたターゲットオブジェクトのプロパティパスを評価するFactoryBean
である。このターゲットオブジェクトは、直接もしくは、ビーン名で指定することができる。これで設定された値は他のビーン定義でプロパティ値もしくはコンストラクタ引数として用いられる。
ここで、他のビーンに名前として使われるパスの例をみてみよう。
// target bean to be referenced by name <bean id="person" class="org.springframework.beans.TestBean" \ singleton="false"> <property name="age"><value>10</value></property> <property name="spouse"> <bean class="org.springframework.beans.TestBean"> <property name="age"><value>11</value></property> </bean> </property> </bean> // will result in 11, which is the value of property 'spouse.age' of bean \ 'person' <bean id="theAge" \ class="org.springframework.beans.factory.config.PropertyPathFactoryBean"> <property name="targetBeanName"><value>person</value></property> <property name="propertyPath"><value>spouse.age</value></property> </bean>
この例では、パスは内部ビーンに対して評価される。
// will result in 12, which is the value of property 'age' of the inner \ bean <bean id="theAge" \ class="org.springframework.beans.factory.config.PropertyPathFactoryBean"> <property name="targetObject"> <bean class="org.springframework.beans.TestBean"> <property name="age"><value>12</value></property> </bean> </property> <property name="propertyPath"><value>age</value></property> </bean>
他にもショートカットの形式があり、ビーン名がプロパティパスとなる。
// will result in 10, which is the value of property 'age' of bean 'person' <bean id="person.age" \ class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
この形式では、選択がビーンの名前になく、このビーンへの参照もパスである同じIDを使わないといけないということを意味する。もちろん、内部ビーンとして使う場合は、いづれにしても参照する必要はない。
<bean id="..." class="..."> <proprty name="age"> <bean id="person.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/> </property> </bean>
この結果の型は特別に実際の定義に設定される。これはほとんどの状況では使う必要ないと思われるが、役に立つこともあるだろう。詳細については、本機能に関するJavaDocを参照してほしい。
FieldRetrievingFactoryBean
はstaticあるいは非staticなフィールド値を検索するFactoryBean
である。これは、public static finalな定数を検索するのによく用いられ、また他のビーンのプロパティ値やコンストラクタ引数を設定するのに用いられる。
以下はstaticField
を使うことによって、どのようにstaticフィールドが取り出されるのかを示す例である。
<bean id="myField" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"> <property \ name="staticField"><value>java.sql.Connection.TRANSACTION_SERIALIZABLE</value></property> \ </bean>
他にもstaticフィールドがビーン名として指定する便利な使い方もある。
<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
これはつまり、ビーンIDになにも選択されていない(従って参照している他のビーンに長い名前が使われていないといけない)ということだが、この方法は、定義するのがとても簡潔で、ビーン参照のためにIDを指定する必要がないので、内部ビーンとして使うのに非常に便利なのだ。
<bean id="..." class="..."> <proprty name="isolation"> <bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/> </property> </bean>
JavaDocにも記述されているように、これは他のビーンの非staticなフィールドにもアクセスが可能だ。
他のクラスが使われる前に、ある種の初期化を実行するために、あるクラスのstaticメソッドもしくは非staticメソッドを呼ぶ必要があることがある。さらに、コンテナにあるほかのビーンのメソッドもしくは、任意のクラスのstaticメソッドを呼んでその結果をビーンにあるプロパティに設定する必要が生じることがある。このような目的のために、MethodInvokingFactoryBean
と呼ばれるヘルパークラスが用いられる。これはstaticメソッドもしくは非staticメソッドを起動した結果の値を返すFactoryBean
である。
でも、この2つめの用途には、以前にも述べたが、factory-method
の方をどんな場合においてもお勧めする。
下記は、なんらかのstaticな初期化を無理やり行うのにこのクラスを使った(XMLベースのBeanFactory
定義にある)ビーン定義の例だ。
<bean id="force-init" \ class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> \ <property \ name="staticMethod"><value>com.example.MyClass.initialize</value></property> \ </bean> <bean id="bean1" class="..." depends-on="force-init"> ... </bean>
このbean1
の定義では、force-init
ビーンを参照するのにdepends-on
属性を使っている。これはまず最初force-init
の初期化を起動する。staticの初期化メソッドが呼ばれ、bena1
がまず最初に初期化される。
下記は、staticなファクトリメソッドを呼ぶのにこのクラスを用いるビーン定義の例である。
<bean id="myClass" \ class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> \ <property \ name="staticMethod"><value>com.whatever.MyClassFactory.getInstance</value></property> \ </bean>
これはJavaシステムプロパティを取得するためにスタティックなメソッドを叩いて、そしてインスタンスメソッドを叩く例だ。ちょっと冗長だけど、でもちゃんと動くよ。
<bean id="sysProps" \ class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> \ <property name="targetClass"><value>java.lang.System</value></property> <property name="targetMethod"><value>getProperties</value></property> </bean> <bean id="javaVersion" \ class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> \ <property name="targetObject"><ref local="sysProps"/></property> <property name="targetMethod"><value>getProperty</value></property> <property name="arguments"> <list> <value>java.version</value> </list> </property> </bean>
ファクトリメソッドにアクセスするほとんどに利用されると思われるが、MethodInvokingFactoryBean
はシングルトンの場合はデフォルトで動作するということに注意して欲しい。ファクトリにオブジェクトを生成するようにコンテナから最初のリクエストがあると、指定されたメソッドが叩かれ、その返り値がキャッシュされると同時にそのリクエストと後続のリクエストに返される。ターゲットメソッドをオブジェクトへ問い合わせがあるたびに起動させるためには、ファクトリ内部のsingleton
プロパティにfalse
が設定されていないといけない。
スタティックなターゲットメソッドは、targetMethod
プロパティに設定されているスタティックメソッドの名前を表す文字列により指定され、そのスタティックメソッドが定義されているクラスがtargetClass
に指定される。反対に、ターゲットインスタンスメソッドはtargetObject
プロパティにターゲットオブジェクトとして設定されることで指定され、そのターゲットオブジェクト上叩くメソッド名としてtargetMethod
プロパティに設定される。これらのメソッド起動の引数はarguments
プロパティの設定で指定される。
コンテナの定義を複数のXMLファイルに分割するのが便利なことがしばしばある。 このXML断片全てによって設定されているアプリケーションコンテキストをロードするひとつの方法は、複数のリソースロケーションを指定するアプリケーションコンテキストコンストラクタを用いる方法だ。ビーンファクトリを使って、各ファイルから定義を繰り返し読み込むのに、ビーン定義リーダが複数回使われる。
一般に、Springチームは上記のアプローチを好んでいる。というのは、コンテナの設定ファイルが今のように他のファイルと組み合わされるということを気にしないでいいからだ。しかしながら、これとは異なる方法は、1つのXMLビーン定義ファイルから、いくつかのimport
要素のインスタンスを使って、いくつかの別のファイルから定義をロードするというものだ。このimport
要素は、ファイル中のインポートを行うbean
要素よりも前にないといけない。ではサンプルを見てみよう。
<beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> . . .
この例では、外部ビーン定義は3つのファイル、services.xml、messageSource.xml、themeSource.xmlからロードされる。このファイルが置かれているパスはインポートを行うファイルから見て相対的なもので、この例では、services.xmlはインポートを行うファイルと同じディレクトリ、もしくはクラスパスになければならないが、messageSource.xmlやthemeSource.xmlはインポートするファイルの前のresources
の場所になければならない。見てわかるように、先頭のスラッシュは実際には無視されるが、相対パスとみなされるので、おそらくスラッシュは付与しないほうがいい。
インポートされるファイルの中身は、一番上位のbeans
要素も含めて、DTD上完全にバリッドなXMLビーン定義ファイルでなければならない。
BeanFactory
とは逆に、プログラム的に生成されることもあるだろうが、例えばContextLoader
を使ってApplicationContext
を宣言的に生成することもできる。もちろん、ApplicationContext
をApplicationContext
の実装を使ってプログラム的に生成することも可能だ。まずは、ContextLoader
とその実装について調べていこう。
ContextLoader
には2つの実装がある。ContextLoaderListener
とContextLoaderServlet
だ。双方は機能的には全く同じだが、リスナーの方はサーブレット2.2準拠なコンテナでは使えないという違いがある。サーブレット2.4仕様からは、ウェブアプリケーションの起動直後に初期化するためにリスナーを必要とされている。多くの2.3準拠のコンテナでは既にこの機能は実装されている。これは、あなたがどのバージョンを使うか次第ではあるが、どれでも同じになるように、ContextLoaderListener
を使うようにすべきだと思う。互換性に関する詳細については、ContextLoaderServlet
のJavaDocを見て欲しい。
ApplicationContext
はContextLoaderListener
を使って以下のように登録することができる。
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/daoContext.xml \ /WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- OR USE THE CONTEXTLOADERSERVLET INSTEAD OF THE LISTENER <servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> -->
このリスナーはContextConfigLocation
パラメータを調べる。もし、このパラメータがなければ、/WEB-INF/applicationContext.xml
がデフォルトとして使用される。存在する場合は、あらかじめ定義されたデリミタ(コンマとセミコロン、スペース)で文字列を分割し、アプリケーションコンテキストを探す位置としてその値が用いられる。前に言ったようにContextLoaderListener
の代わりにContextLoaderServlet
を使うこともできる。このサーブレットもリスナーと同じようにcontextConfigLocation
パラメータを使う。
アプリケーション内のコードの大多数は最もDependency Injection(Inversion of Control)スタイルで書かれていて、そのコードはBeanFactory
やApplicationContext
コンテナにあって、依存関係は生成時にコンテナにより注入される。またコンテナには完全に依存しない。しかしながら、他のコードと一緒に結合される必要があるような小さな結合層のコードでは、BeanFactory
やApplicationContext
へシングルトン(もしくは擬似シングルトン)スタイルのアクセスが必要になることがたまにある。例えば、サードパーティ製のコードが新しいオブジェクトをBeanFactory
の外でこのオブジェクトを取得できないのに直接(つまり、Class.forName()
スタイルで)生成しようとするかもしれない。もし、このサードパーティのコードにより生成されたオブジェクトが小さなスタブかあるいはプロキシで、デリゲートする本当のオブジェクトを取得するのにシングルトンスタイルでBeanFactory/ApplicationContext
にアクセスする場合でも、inversion of controlはほとんどのコード(BeanFactory
からできたオブジェクト)で保たれている。つまりほとんどのコードはコンテナや、あるいはどうやってアクセスされるかに依存せず、他のコードと分離されており、全ての利点が生かされている。EJBでもBeanFactory
で生成されたプレインなJavaで実装されたオブジェクトへのデリケートに、このスタブ/プロキシアプローチを使っている。BeanFactory
が理想的にシングルトンである必要がない場合は、メモリの使い方や初期化の回数(HibernateのSessionFactory
のようなBeanFactory
でビーンを使う場合)という点で、各ビーンがそれぞれ非シングルトンのBeanFactory
を使うのは非現実的かもしれない。
別の例として、複雑な多層(つまり、様々なJARファイル、EJB、EARとしてパッケージ化されたWARファイル)のJ2EEアプリケーションにおいて、各層がそれぞれ自前のApplicationContext
定義を(効率よく階層をなして)持っている場合、一番上の層がWebアプリ(WAR)が1つしかない場合の好ましいアプローチは、単に、各層の複数のXML定義ファイルから合成ApplicationContext
を1つだけ生成するというものだ。ApplicationContext
の派生は全てこの方法で複数のXML定義ファイルから生成される。しかしながら、一番上の階層に同様のWebアプリが複数ある場合、その下の層からのほとんど同一のビーン定義で構成される各WebアプリごとにApplicationContext
を生成することは、メモリ使用量が増えることで問題や、初期化に時間がかかるビーン(つまり、HibernateのSessionFactory
)を複数コピーを生成する問題や、副作用による問題を引き起こすかもしれないので問題といえるもしれない。それに対して、ContextSingletonBeanFactoryLocator
やSingletonBeanFactoryLocator
のようなクラスは多階層な(つまり、あるものが別の親になっている)BeanFactory
やApplicationContext
を効率よくシングルトン方式でオンデマンドで読み込まれるのに利用される。これは、そのウェブアプリ用ApplicationContext
の親として用いられる。その結果、この下位層のビーン定義は必要なときしかロードされず、また高々1回しかロードされないのだ。
SingletonBeanFactoryLocator
とContextSingletonBeanFactoryLocator
を使った詳しい例はhttp://www.springframework.org/docs/api/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.htmlとhttp://www.springframework.org/docs/api/org/springframework/context/access/ContextSingletonBeanFactoryLocator.htmlにあるのでJavaDocで見ることができる。
EJBの章で触れられているように、Springの便利なEJBのための基底クラスは通常、非シングルトンBeanFactoryLocator
の実装を使う。これは、必要であればSingletonBeanFactoryLocator
や、ContextSingletonFactoryLocator
を使って簡単に差し替えることができる。