コンテナー拡張ポイント
通常、アプリケーション開発者は ApplicationContext
実装クラスをサブクラス化する必要はありません。代わりに、Spring IoC コンテナーは、特別な統合インターフェースの実装をプラグインすることにより拡張できます。次のいくつかのセクションでは、これらの統合インターフェースについて説明します。
BeanPostProcessor
を使用して Bean をカスタマイズする
BeanPostProcessor
インターフェースは、独自の(またはコンテナーのデフォルトをオーバーライドする)インスタンス化ロジック、依存関係解決ロジックなどを提供するために実装できるコールバックメソッドを定義します。Spring コンテナーが Bean のインスタンス化、構成、初期化を完了した後にカスタムロジックを実装する場合は、1 つ以上のカスタム BeanPostProcessor
実装をプラグインできます。
複数の BeanPostProcessor
インスタンスを構成でき、order
プロパティを設定することにより、これらの BeanPostProcessor
インスタンスの実行順序を制御できます。このプロパティを設定できるのは、BeanPostProcessor
が Ordered
インターフェースを実装している場合のみです。独自の BeanPostProcessor
を作成する場合は、Ordered
インターフェースの実装も検討する必要があります。詳細については、BeanPostProcessor
(Javadoc) および Ordered
(Javadoc) インターフェースの javadoc を参照してください。BeanPostProcessor
インスタンスのプログラムによる登録に関する注意も参照してください。
実際の Bean 定義(つまり、Bean を定義する設計図)を変更するには、代わりに |
org.springframework.beans.factory.config.BeanPostProcessor
インターフェースは、正確に 2 つのコールバックメソッドで構成されています。このようなクラスをポストプロセッサーとしてコンテナーに登録すると、コンテナーによって作成される Bean インスタンスごとに、ポストプロセッサーはコンテナー初期化メソッド (InitializingBean.afterPropertiesSet()
や公表されている init
法など) が呼び出される前と Bean 初期化コールバックの後の両方で、コンテナーからコールバックを取得します。ポストプロセッサーは、コールバックを完全に無視するなど、Bean インスタンスに対して任意のアクションを実行できます。Bean ポストプロセッサーは通常、コールバックインターフェースをチェックするか、プロキシで Bean をラップします。一部の Spring AOP インフラストラクチャクラスは、プロキシ折り返しロジックを提供するために Bean ポストプロセッサーとして実装されます。
ApplicationContext
は、BeanPostProcessor
インターフェースを実装する構成メタデータで定義されている Bean を自動的に検出します。ApplicationContext
は、これらの Bean をポストプロセッサーとして登録し、後で Bean の作成時に呼び出すことができるようにします。Bean ポストプロセッサーは、他の Bean と同じ方法でコンテナーにデプロイできます。
構成クラスで @Bean
ファクトリメソッドを使用して BeanPostProcessor
を宣言する場合、ファクトリメソッドの戻り値の型は、実装クラス自体または少なくとも org.springframework.beans.factory.config.BeanPostProcessor
インターフェースである必要があり、その Bean のポストプロセッサーの性質を明確に示すことに注意してください。そうしないと、ApplicationContext
は完全に作成する前に型ごとに自動検出できません。コンテキスト内の他の Bean の初期化に適用するには、BeanPostProcessor
を早期にインスタンス化する必要があるため、この早期型検出は重要です。
BeanPostProcessor インスタンスをプログラムで登録する BeanPostProcessor 登録の推奨アプローチは ApplicationContext 自動検出によるものですが(前述)、addBeanPostProcessor メソッドを使用して、ConfigurableBeanFactory に対してプログラムで登録できます。これは、登録前に条件付きロジックを評価する必要がある場合、または階層内のコンテキスト間で Bean ポストプロセッサーをコピーする場合にも役立ちます。ただし、プログラムで追加された BeanPostProcessor インスタンスは Ordered インターフェースを考慮しないことに注意してください。ここで、実行の順序を決定するのは登録の順序です。また、プログラムで登録された BeanPostProcessor インスタンスは、明示的な順序に関係なく、自動検出によって登録されたインスタンスの前に常に処理されることに注意してください。 |
BeanPostProcessor インスタンスと AOP 自動プロキシ
そのような Bean の場合、情報ログメッセージ オートワイヤーまたは |
以下の例は、ApplicationContext
で BeanPostProcessor
インスタンスを作成、登録、使用する方法を示しています。
サンプル: Hello World、BeanPostProcessor
スタイル
この最初の例は、基本的な使用箇所を示しています。この例は、コンテナーによって作成された各 Bean の toString()
メソッドを呼び出し、結果の文字列をシステムコンソールに出力するカスタム BeanPostProcessor
実装を示しています。
次のリストは、カスタム BeanPostProcessor
実装クラス定義を示しています。
Java
Kotlin
package scripting;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
// simply return the instantiated bean as-is
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean; // we could potentially return any object reference here...
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
return bean;
}
}
package scripting
import org.springframework.beans.factory.config.BeanPostProcessor
class InstantiationTracingBeanPostProcessor : BeanPostProcessor {
// simply return the instantiated bean as-is
override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any? {
return bean // we could potentially return any object reference here...
}
override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? {
println("Bean '$beanName' created : $bean")
return bean
}
}
次の beans
要素は InstantiationTracingBeanPostProcessor
を使用します。
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
https://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>
<!--
when the above bean (messenger) is instantiated, this custom
BeanPostProcessor implementation will output the fact to the system console
-->
<bean class="scripting.InstantiationTracingBeanPostProcessor"/>
</beans>
InstantiationTracingBeanPostProcessor
が単に定義されていることに注目してください。名前さえも持たず、Bean であるため、他の Bean と同様に依存関係を注入できます。(上記の構成では、Groovy スクリプトによってサポートされる Bean も定義しています。Spring 動的言語サポートについては、動的言語サポートというタイトルの章で詳しく説明しています。)
次の Java アプリケーションは、前述のコードと構成を実行します。
Java
Kotlin
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 = ctx.getBean("messenger", Messenger.class);
System.out.println(messenger);
}
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = ClassPathXmlApplicationContext("scripting/beans.xml")
val messenger = ctx.getBean<Messenger>("messenger")
println(messenger)
}
上記のアプリケーションの出力は次のようになります。
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961 org.springframework.scripting.groovy.GroovyMessenger@272961
BeanFactoryPostProcessor
を使用した構成メタデータのカスタマイズ
次に見る拡張ポイントは org.springframework.beans.factory.config.BeanFactoryPostProcessor
です。このインターフェースのセマンティクスは BeanPostProcessor
のセマンティクスと似ていますが、大きな違いが 1 つあります。BeanFactoryPostProcessor
は Bean 構成メタデータで動作します。つまり、Spring IoC コンテナーは、BeanFactoryPostProcessor
インスタンス以外の Bean をコンテナーがインスタンス化する前に、BeanFactoryPostProcessor
が構成メタデータを読み取り、潜在的にそれを変更できるようにします。
複数の BeanFactoryPostProcessor
インスタンスを構成でき、order
プロパティを設定することにより、これらの BeanFactoryPostProcessor
インスタンスの実行順序を制御できます。ただし、BeanFactoryPostProcessor
が Ordered
インターフェースを実装している場合にのみ、このプロパティを設定できます。独自の BeanFactoryPostProcessor
を作成する場合は、Ordered
インターフェースの実装も検討する必要があります。詳細については、BeanFactoryPostProcessor
(Javadoc) および Ordered
(Javadoc) インターフェースの javadoc を参照してください。
実際の Bean インスタンス(つまり、構成メタデータから作成されたオブジェクト)を変更する場合は、代わりに また、 |
Bean ファクトリポストプロセッサーは、コンテナーを定義する構成メタデータに変更を適用するために、ApplicationContext
内で宣言されたときに自動的に実行されます。Spring には、PropertyOverrideConfigurer
や PropertySourcesPlaceholderConfigurer
など、事前定義された多数の Bean ファクトリポストプロセッサーが含まれています。カスタム BeanFactoryPostProcessor
を使用して、たとえば、カスタムプロパティエディターを登録することもできます。
ApplicationContext
は、BeanFactoryPostProcessor
インターフェースを実装する Bean にデプロイされた Bean を自動的に検出します。適切なタイミングで、これらの Bean を Bean ファクトリポストプロセッサーとして使用します。これらのポストプロセッサー Bean は、他の Bean と同様にデプロイできます。
BeanPostProcessor の場合と同様、通常、遅延初期化用に BeanFactoryPostProcessor を構成することは望ましくありません。他の Bean が Bean(Factory)PostProcessor を参照していない場合、そのポストプロセッサーはインスタンス化されません。遅延初期化のマークは無視され、<beans /> 要素の宣言で default-lazy-init 属性を true に設定しても、Bean(Factory)PostProcessor は即座にインスタンス化されます。 |
サンプル: クラス名の置換 PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer
を使用して、標準の Java Properties
形式を使用することにより、別のファイルの Bean 定義からプロパティ値を外部化できます。そうすることで、アプリケーションをデプロイする人は、複雑な、またはコンテナーの XML 定義ファイルを変更するリスクなしに、データベース URL やパスワードなどの環境固有のプロパティをカスタマイズできます。
プレースホルダー値を持つ DataSource
が定義されている次の XML ベースの構成メタデータフラグメントを検討してください。
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations" value="classpath:com/something/jdbc.properties"/>
</bean>
<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
ファイルから構成されたプロパティを示しています。実行時に、DataSource の一部のプロパティを置き換える PropertySourcesPlaceholderConfigurer
がメタデータに適用されます。置換する値は、Ant、log4j、JSP EL スタイルに従う ${property-name}
形式のプレースホルダーとして指定されます。
実際の値は、標準 Java Properties
形式の別のファイルから取得されます。
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
${jdbc.username}
文字列は実行時に値 "sa" に置き換えられ、プロパティファイル内のキーと一致する他のプレースホルダー値にも同じことが当てはまります。PropertySourcesPlaceholderConfigurer
は、Bean 定義のほとんどのプロパティと属性のプレースホルダーをチェックします。さらに、プレースホルダーのプレフィックスとサフィックスをカスタマイズできます。
Spring 2.5 で導入された context
名前空間を使用すると、専用の構成要素でプロパティプレースホルダーを構成できます。次の例に示すように、1 つ以上の場所を location
属性のコンマ区切りリストとして指定できます。
<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
PropertySourcesPlaceholderConfigurer
は、指定した Properties
ファイルのプロパティを探すだけではありません。デフォルトでは、指定されたプロパティファイルでプロパティが見つからない場合、Spring Environment
プロパティおよび通常の Java System
プロパティに対してチェックします。
必要なプロパティを持つ特定のアプリケーションに対して、そのような要素を 1 つだけ定義する必要があります。個別のプレースホルダー構文 ( 置換に使用されるプロパティのソースをモジュール化する必要がある場合は、複数のプロパティプレースホルダーを作成しないでください。むしろ、使用するプロパティを集めた独自の |
実行時にクラスを有効なクラスに解決できない場合、Bean の解決は、作成されようとしているときに失敗します。これは、lazy-init 以外の Bean の |
サンプル: PropertyOverrideConfigurer
別の Bean ファクトリポストプロセッサーである PropertyOverrideConfigurer
は PropertySourcesPlaceholderConfigurer
に似ていますが、後者とは異なり、元の定義には Bean プロパティのデフォルト値を設定することも、値をまったく設定しないこともできます。オーバーライドする Properties
ファイルに特定の Bean プロパティのエントリがない場合、デフォルトのコンテキスト定義が使用されます。
Bean 定義はオーバーライドされることを認識していないため、オーバーライド構成が使用されていることは XML 定義ファイルからすぐにはわかりません。同じ Bean プロパティに異なる値を定義する複数の PropertyOverrideConfigurer
インスタンスの場合、オーバーライドメカニズムにより、最後のインスタンスが優先されます。
プロパティファイルの構成行の形式は次のとおりです。
beanName.property=value
次のリストは、フォーマットの例を示しています。
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
このサンプルファイルは、driverClassName
および url
プロパティを持つ dataSource
という Bean を含むコンテナー定義で使用できます。
オーバーライドされる最終プロパティを除くパスのすべてのコンポーネントがすでに null でない(おそらくコンストラクターによって初期化される)限り、複合プロパティ名もサポートされます。次の例では、tom
Bean の fred
プロパティの bob
プロパティの sammy
プロパティがスカラー値 123
に設定されます。
tom.fred.bob.sammy=123
指定されたオーバーライド値は常にリテラル値です。それらは Bean 参照に変換されません。この規則は、XML Bean 定義の元の値が Bean 参照を指定している場合にも適用されます。 |
Spring 2.5 で導入された context
名前空間を使用すると、次の例に示すように、専用の構成要素でプロパティのオーバーライドを構成できます。
<context:property-override location="classpath:override.properties"/>
FactoryBean
を使用したインスタンス化ロジックのカスタマイズ
自身がファクトリであるオブジェクトに対して org.springframework.beans.factory.FactoryBean
インターフェースを実装できます。
FactoryBean
インターフェースは、Spring IoC コンテナーのインスタンス化ロジックへのプラグインのポイントです。(潜在的に)冗長な量の XML ではなく Java でより適切に表現される複雑な初期化コードがある場合、独自の FactoryBean
を作成し、そのクラス内に複雑な初期化を記述してから、カスタム FactoryBean
をコンテナーにプラグインできます。
FactoryBean<T>
インターフェースには 3 つの方法があります。
T getObject()
: このファクトリが作成するオブジェクトのインスタンスを返します。このファクトリがシングルトンを返すかプロトタイプを返すかに応じて、インスタンスを共有できます。boolean isSingleton()
: このFactoryBean
がシングルトンを返す場合はtrue
を返し、それ以外の場合はfalse
を返します。このメソッドのデフォルトの実装はtrue
を返します。Class<?> getObjectType()
: 型が事前にわからない場合、getObject()
メソッドまたはnull
によって返されたオブジェクト型を返します。
FactoryBean
の概念とインターフェースは、Spring Framework 内のさまざまな場所で使用されています。FactoryBean
インターフェースの 50 以上の実装には、Spring 自体が付属しています。
コンテナーが生成する Bean ではなく実際の FactoryBean
インスタンス自体をコンテナーに要求する必要がある場合は、ApplicationContext
の getBean()
メソッドを呼び出すときに、Bean の id
の前にアンパサンド記号(&
)を付けます。myBean
の id
を持つ特定の FactoryBean
の場合、コンテナーで getBean("myBean")
を呼び出すと、FactoryBean
の積が返されますが、getBean("&myBean")
を呼び出すと、FactoryBean
インスタンス自体が返されます。