BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル Spring 2.5の新機能―Part 1

Spring 2.5の新機能―Part 1

ブックマーク

序論

Springフレームワークは最初から、企業のアプリケーション開発を簡略化するという目標に常に照準を合わせながら、同時に、複雑な問題に非侵襲的で強力な解決策を提供してきました。一年余り前にリリースされたSpring 2.0では、こうしたテーマが新たなレベルへと進みました。XMLスキーマのサポートとカスタムのネーム空間により、XMLベースのコンフィギュレーション量が減りました。Java 5以上を使用しているデベロッパーは、ジェネリックスやアノテーションなどの新しい言語機能を利用するSpringライブラリを活用できます。AspectJの式言語と緊密に一体化しているため、Spring管理オブジェクトの分類がうまく定義されていれば、その全分類で動作を非侵襲的に追加可能なのです。

最近リリースされたSpring 2.5でもこの流れを継承し、さらなる簡略化と新規の強力な機能を提供していますが、特にJava 5以上の利用者に恩恵が大きいです。こうした機能には、アノテーション駆動型の依存性注入や、メタデータにXMLではなくアノテーションを使ってクラスパス上のSpringコンポーネントを自動検出、ライフサイクルメソッドのアノテーション・サポート、アノテートしたメソッドにリクエストをマッピングするための新規Webコントローラー・モデル、テストフレームワーク内でのJunit 4のサポート、Spring XMLネーム空間への新規追加などがあります。

この記事は、こうした新機能を探求する3回シリーズの第1回目です。今回の記事では、Springアプリケーション・コンテキストの中核に位置する簡略化されたコンフィギュレーション並びに新しいアノテーションベースの機能性に焦点を当てます。第2回ではWeb階層で利用可能になった新機能、最終回では統合と検査で利用できる追加機能にスポットライトを当てます。今回のシリーズ記事内で使用する例の大部分は、Spring PetClinicのサンプルアプリケーションを基にしています。このサンプルは最新Springの機能性を試演する場として最近リファクタされたもので、Spring Framework Downloadページ(サイト・英語)のSpring 2.5配布内に入っています。PetClinicアプリケーションの構築とデプロイに関する説明については、「samples/petclinic」ディレクトリ内の「readme.txt」ファイルを見るとよいでしょう。ここで論じている新テクニックをマスターするには、紹介した機能をPetClinicアプリケーションで試すのが最良の方法でしょう。

SpringのJSR-250アノテーションに対するサポート

Java EEバージョン5では「Common Annotations for the Java Platform」(Javaプラットフォーム用共通アノテーション)が導入され、また、Java SEにもバージョン6から入れられるようになりました。2006年5月、BEA SystemsはInterface21とPitchfork(サイト・英語)というプロジェクトで協力すると発表しました(source)。Pitchforkは、Java EE 5プログラミング・モデルのSpringベースでの実装を提供するもので、注入、遮断、処理用のJSR-250アノテーションおよびEJB 3アノテーション(JSR-220)をサポートします。バージョン2.5の時点で、Springフレームワークのコアが現在サポートしているJSR-250アノテーションは以下のとおりです。

  • @Resource
  • @PostConstruct
  • @PreDestroy

Springではこうしたアノテーションをアプリケーションサーバーの有無にかかわらずあらゆる環境でサポートしており、統合検査さえ対象になります。このサポートを有効にするには、次のように単一のSpringのポストプロセッサを登録するだけです。

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/> 

@Resourceアノテーション

@Resourceアノテーションは「名前つきリソース」の依存性注入を可能にします。Java EEアプリケーション内では通常、JNDIコンテキストに結びついたオブジェクトに翻訳します。Springは、JNDIルックアップを通じてオブジェクトを解決する@Resource の利用法をサポートこそしていますが、デフォルトでは、@Resourceアノテーションに提供された名前と一致する「Bean名」を持つSpring管理オブジェクトが注入されます。次の例でSpringは、「dataSource」というBean名がついたSpring管理オブジェクトのリファレンスをアノテートされたセッターメソッドに渡します。

@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

@Resource. を使ってフィールドを直接アノテートすることもできます。セッターメソッドを公開しないことで、コードがより簡潔になり、不変性の強化という付加的な利益までもたらしmさう。以下に説明しているとおり、@Resource アノテーションには明示的な文字列値さえ必要ありません。値の提供がないと、フィールド名がデフォルトで使われます。

@Resource
private DataSource dataSource; // inject the bean named 'dataSource'

セッターメソッドに適用されると、デフォルト名は一致するプロパティから付けられます。すなわち、「setDataSource」という名のメソッドは、解決すると「dataSource」という名称のプロパティにもなるということです。

private DataSource dataSource;
@Resource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

明示的に提供された名称なしで@Resource を使用し、デフォルト名のSpring管理オブジェクトが見つからない場合、注入メカニズムはタイプの一致を代用します。依存性のタイプに一致するSpring管理オブジェクトがたった一つある場合、それが注入されます。この機能を無効にするには、CommonAnnotationBeanPostProcessor「fallbackToDefaultTypeMatch」プロパティを「false」に設定しmさう(デフォルトは「true」)。

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="fallbackToDefaultTypeMatch" value="false"/>
</bean>

前述したように、@Resourceでアノテートされた依存性を解決する際、SpringはJNDIルックアップをサポートします。@Resourceでアノテートされた全依存性に直接的なJNDIルックアップを強制するには、CommonAnnotationBeanPostProcessor「alwaysUseJndiLookup」フラグを「true」に設定します(デフォルトは「false」)。

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="true"/>
</bean>

あるいは、「resource-ref-mappings」として指定したグローバルJNDI名に基づいたルックアップを有効化するには、 @Resourceアノテーション内の「mappedName」属性を提供します。ターゲットオブジェクトが実はJNDIリソースという場合でさえ、Spring管理オブジェクトの参照を実行するようお勧めします。そうすればインダイレクションのレベルを提供することになり、カップリングの度合いが減少します。Spring 2.0から利用可能になった追加のネーム空間を使えば、SpringにJNDIルックアップの処理を委任するBean定義が自明かつ簡潔になります。

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/> 

このアプローチの利点は、インダイレクションのレベルによりデプロイメントの柔軟性が高まることです。たとえば、スタンドアロンのシステム検査環境では、JNDIレジストリが必要であってはなりません。そのようなケースでは、システム検査コンフィギュレーション内で、次のような代わりのBean定義を提供できます。

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>

余談ですが、上の例では実際のJDBC接続プロパティは、与えられた${placeholder}トークンにキーが一致する場所で解決されます。これを達成するには、PropertyPlaceholderConfigurerと呼ばれるSpringのBeanFactoryPostProcessor実装を登録します。その他のコンフィギュレーションより頻繁な変更が必要とされる可能性のあるこうしたプロパティ(多くは環境特異的なプロパティ)を、外部に置くテクニックとしてよく使われます。

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>

Spring 2.5では「context」ネーム空間が追加されたことで、プロパティ・プレースホルダー・コンフィギュレーションより簡潔な代替が使えるようになりました。

<context:property-placeholder location="classpath:jdbc.properties"/> 

ライフサイクル・アノテーションの@PostConstructと@PreDestroy

@PostConstruct@PreDestroyアノテーションを使って、それぞれSpring初期化と破棄のコールバックをトリガできます。この機能は拡張しますが、Spring 2.5以前のバージョンにあるこうしたコールバックを提供するオプション2つに取って代わるわけではありません。一つ目のオプションは、InitializingBeanインターフェースとDisposableBeanインターフェースの片方もしくは両方を実装します。この2つのインターフェースはそれぞれ、単一のコールバック・メソッドの実装〔それぞれafterPropertiesSet()およびdestroy()〕を必要とします。このインターフェース・ベースのアプローチは、こうしたインターフェースを実装するあらゆるSpring管理オブジェクトを自動的に認識するSpringの機能を利用しているため、追加のコンフィギュレーションは必要ありません。その一方で、Springの重要な目標は、可能な限り非侵襲的になることです。そのため、Springに特異的なインターフェースを実装する代わりに、多数のSpringユーザーが、各自で初期化、破棄メソッドを提供するという2番目のオプションを活用してきました。このアプローチでは侵襲性は低くなりますが、欠点は、「Bean」要素で「init-method」「destroy-method」属性の両方もしくは片方を明示的に宣言する必要があることです。デベロッパーの管理外にあるコードからコールバックを呼び出す必要がある場合など、明示的なコンフィギュレーションが必要なこともあります。PetClinicアプリケーションでは、このシナリオを説明しています。JDBCコンフィギュレーションを使って動作させる場合、サードパーティーのDataSourseを使い、「破棄メソッド」を明示的に宣言します。また、スタンドアロンでコネクション・プーリングするDataSourceは、「dataSource」向けのもう一つのデプロイメント選択肢であり、コードを変更する必要は全くないので、ご注意ください。

<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>

Spring 2.5では、オブジェクトが初期化時にコールバック・メソッドの呼び出しを必要とする場合、そのメソッドは@PostConstructアノテーションを使ってアノテートできます。たとえば、起動時にファイルディレクトリのポーリングを開始する必要があるバックグラウンドタスクを考えてみましょう。

public class FilePoller {

@PostConstruct
public void startPolling() {
...
}
...
}

同様に、Spring管理オブジェクトについて@PreDestroyを使ってアノテートしたメソッドは、そのオブジェクトをホスティングしているアプリケーション・コンテキストを閉じると呼び出されます。

public class FilePoller {

@PreDestroy
public void stopPolling() {
...
}
...
}

JSR-250アノテーションのサポートを追加したことにより、Spring 2.5は以前のライフサイクルメソッド選択をしたときの2つの利点を兼ね備えています。メソッドレベルのアノテーションとして@PostConstruct@PreDestroyを追加することで、Springが管理するコンテキスト内で十分コールバックをトリガできます。すなわち、XMLベースのコンフィギュレーションを何ら追加する必要がありません。同時に、アノテーションはJava言語そのものの一部になっており(バージョン6ではJava SEにさえ含まれている)、そのため、Springに特異的なインポートが不要です。アノテーションには他の環境で解釈されるべきセマンティクスを表示するという付加的な利点があり、時間の経過とともに、Javaデベロッパは、サードパーティーのライブラリ内でこうしたアノテーションの使用をもっと頻繁に見るようになるでしょう。最後に、アノテーションベースのライフサイクル・コールバックがもたらす興味深い成り行きの一つに、1個以上のメソッドがどのアノテーションも持つことがあり、すべてのアノテートされたメソッドが呼び出される可能性があることが挙げられます。

@Resource@PostConstruct@PreDestroyアノテーションで前述した全動作を有効にするには、以前示したように、SpringのCommonAnnotationBeanPostProcessor向けに単一Bean定義を提供します。2.5の新しい「context」ネーム空間を使えば、さらに簡潔な選択肢さえ可能です。

<context:annotation-config/> 

この単一要素を入れることにより、CommonAnnotationBeanPostProcessorを登録するだけでなく、この次の項で説明する動作のオートワイヤリングも可能になります。CommonAnnotationBeanPostProcessor、@WebServiceRefおよび@EJBアノテーションのサポートさえ提供します。これに関しては、この記事シリーズの第3回目で、エンタープライズ統合用のSpring 2.5新機能とともに取り扱う予定です。

アノテーションの粒度の細かいオートワイヤリング

Springのオートワイヤリングに対するサポートを取り扱ったドキュメンテーションには、粒度の粗いオートワイヤリング・メカニズムが原因で警告が載っていることが多いです。Spring 2.5以前では、コンストラクタやセッターのタイプ別、セッターの名称別、自動検出(コンストラクタもしくはセッターのタイプ別のいずれかでオートワイヤするとSpringが選択)というふうに、様々なアプローチでオートワイヤリングを設定できました。このように多様な選択肢があれば柔軟度は増しますが、粒度が非常に細かい制御を提供する選択肢はありません。つまり、Spring 2.5以前では、オブジェクトのセッターメソッドの特定サブセットをオートワイヤしたり、あるプロパティをタイプ別に、その他を名前別にオートワイヤしたりするのは不可能でした。その結果、プロトタイピングや検査向けにオートワイヤする利点を認めたSpringユーザーは多数いましたが、実動システムの保守やサポートとなると、明示的なコンフィギュレーションで冗長性が追加されることになっても、それによって得られる明確化にはとても価値があると、大勢のユーザーの意見が一致するのです。

しかし、Spring 2.5では大幅にランドスケープが変わっています。前述したように、JSR-250 @Resourceアノテーションをサポートすることにより、今ではオートワイヤリングの選択肢が拡張し、メソッドごともしくはフィールドごとの基準で名前付きリソースのオートワイヤリングが可能になりました。しかし、@Resourceアノテーション単独では限界があります。そのためSpring 2.5は@Autowiredアノテーションを導入し、さらに制御レベルを上げています。この項で説明した動作を有効化するには、単一Beanの定義を登録します。

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> 

あるいは、これまでに示したように「context」ネーム空間がより簡潔な代替を提供します。こうすれば、この記事で論じているポストプロセッサ(AutowiredAnnotationBeanPostProcessorおよびCommonAnnotationBeanPostProcessor)に加えて、Spring 2.0で導入されたアノテーションベースのポストプロセッサ(RequiredAnnotationBeanPostProcessorおよびPersistenceAnnotationBeanPostProcessor)も有効化できます。

<context:annotation-config/> 

@Autowiredアノテーションを使えば、タイプが一致する依存性の注入が可能です。この動作は、フィールド、コンストラクタ、メソッドで有効です。実際、アウトワイヤしたメソッドは「セッター」メソッドである必要はなく、複数のパラメータを受け取ることさえできます。以下は完全に許容範囲です。

@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

@Autowiredアノテーションでマークした依存性はデフォルトで、必須として取り扱われます。しかし、「required」属性を「false」に設定すれば、そのうちのどの依存性も任意と宣言できます。以下の例では、コンテキスト内にSomeStrategyタイプのSpring管理オブジェクトが見つからない場合、DefaultStrategyが使われます。

@Autowired(required=false)
private SomeStrategy strategy = new DefaultStrategy();

予想されるタイプのオブジェクトがSpringのコンテキストに2個以上存在すると、タイプ別のオートワイヤリングは間違いなくあいまいな結果になります。要求された依存性のBeanが正確に1個でない場合、オートワイヤリング・メカニズムはデフォルトでフェイルするようになっています。同様に、あらゆる任意のプロパティについて、2個以上の候補が存在する場合にはフェイルします(複数の任意候補が存在する場合や候補が存在しない場合は、単純にそのプロパティをスキップします)。このようなコンフリクトを回避するために、多数のコンフィギュレーション・オプションがあります。

コンテキスト内に所定タイプのプライマリ・インスタンスが一つあるとき、そのタイプのBean定義には「primary」属性がなければなりません。このアプローチは、コンテキスト内に他のインスタンスが存在する可能性のある場合にうまく機能しますが、非プライマリ・インスタンスは常に明示的にコンフィギュアされています。

<bean id="dataSource" primary="true" ... /> 

もっと制御が必要な場合は、オートワイヤしたあらゆるフィールド、コンストラクタ引数、メソッド・パラメータを@Qualifierアノテーションを使ってさらにアノテートできます。限定子にString値が入っていることもあり、その場合、Springは名前による一致を試みます。

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource;

@Qualifierが別個のアノテーションとして存在する主な理由は、そうすれば、コンストラクタ引数もしくはメソッド・パラメータのレベルで適用させながら、@Autowiredアノテーションをコンストラクタもしくはメソッドそのものに使えるからです。

@Autowired
public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o) { ... }

@Qualifierが別個のアノテーションであることにより、カスタム化においてさらにたくさんの利益をもたらします。オートワイヤリングプロセスでは、ユーザー定義のアノテーションが限定子の役割を果たすこともあります。これを達成する一番簡単な方法は、@Qualifierそのものをメタアノテーションとして使い、カスタムアノテーションをアノテートすることです。

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface VetSpecialty { ... }

カスタムアノテーションには、名前による一致のための値をオプションで入れてよいのですが、もっと一般的には「マーカー」アノテーションとして使ったり、限定子プロセスにさらに意味を持たせる値を定義したりします。たとえば、以下の抜書きは、タイプ別で一致する候補の中から、適した候補でオートワイヤされるべきフィールドを示しています。

@Autowired
@VetSpecialty("dentistry")
private Clinic dentistryClinic;

この依存性解決のターゲット用にXMLコンフィギュレーションを使うとき、「qualifier」(限定子)サブ要素がBean定義に追加になることもあります。コンポーネントスキャニングに関する次項では、非XML代替を紹介します。

<bean id="dentistryClinic" class="samples.DentistryClinic">
<qualifier type="example.VetSpecialty" value="dentistry"/>
</bean>

@Qalifierアノテーションへの依存性は何であれ回避するには、Springコンテキスト内でCustomAutowireConfigurerのBean定義を提供し、カスタムのアノテーションタイプすべてを直接定義します。

<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.VetSpecialty</value>
</set>
</property>
</bean>

これでカスタム限定子が明示的に宣言され、@Qualifierメタアノテーションはもはや不要です。

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface VetSpecialty { ... }

関連した注目点に、AutowiredAnnotationBeanPostProcessorをコンフィギュレーションする時に、@Autowiredアノテーション自体を入れ替えることさえ可能なことが挙げられます。

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="autowiredAnnotationType" value="example.Injected"/>
</bean>

大抵のケースでは、オートワイヤリングプロセスの粒度の細かい制御を達成する上で、カスタムの「マーカー」アノテーションを定義する機能と、名前もしくはその他のセマンティック値と一致させるオプションを組み合わせれば、十分なはずです。しかし、Springではさらに、限定子アノテーションに関する任意属性がいくつあっても、サポートしています。たとえば、以下は非常に粒度の細かい限定子の仮定例です。

@SpecializedClinic(species="dog", breed="poodle")
private Clinic poodleClinic;

カスタムの限定子実装がこうした属性を定義します。

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface SpecializedClinic {

String species();

String breed();

}

カスタム限定子の属性は次に、Bean定義のXML内にある、「qualifier」(限定子)アノテーションの「attribute」(属性)サブ要素に対して符合することができます。こうした要素はキー/値のペアを提供するのに使用されます。

<bean id="poodleClinic" class="example.PoodleClinic">
<qualifier type="example.SpecializedClinic">
<attribute key="species" value="dog"/>
<attribute key="breed" value="poodle"/>
</qualifier>
</bean>

これまでに説明したオートワイヤリングは全て、単一インスタンス向けですが、インスタンスのコレクションもサポートしています。コンテキスト内にある特定タイプの全Spring管理オブジェクトを取得する必要があればいつでも、厳密に型が指定された(strongly-typed) Collectionへ単に@Autowiredアノテーションを追加すればすむのです。

@Autowired
private List allClinics;

この項での指摘に値する最後の機能は、Springの「Aware」インターフェースの代わりにオートワイヤリングを使うことです。Spring 2.5以前では、オブジェクトがSpringのコンテキストResourceLoaderへの参照を必要とすると、ResourceLoaderAwareを実装でき、それによりsetResourceLoader(ResourceLoader resourceLoader)メソッドを介してSpringはこの依存性を提供できます。同じテクニックを適用し、Spring管理のMessageSourceへのリファレンスを取得できますし、ApplicationContext自体へのリファレンスさえ取得できます。Spring 2.5のユーザなら、この動作はオートワイヤリング全体で完全サポートされています(こうしたSpringに特異的な依存性を含めることについては常に慎重に検討すべきであり、ビジネスロジックからは完全に切り離された「インフラ」コード内でのみ通常は利用すべきことをここに記しておきます)。

@Autowired
private MessageSource messageSource;

@Autowired
private ResourceLoader resourceLoader;

@Autowired
private ApplicationContext applicationContext;

Springコンポーネントの自動検出

バージョン2.0からSpringは「ステレオタイプ」のアノテーションというコンセプトを導入し、データアクセスコードのマーカーとして@Repositoryアノテーションが機能するようにしました。Spring 2.5では@Serviceおよび@Controlleという2種類の新規アノテーションが追加になり、一般的な三階層アーキテクチャ(データアクセス・オブジェクト、サービス、Webコントローラー)向けの役割指定が完成しました。Spring 2.5は包括的な@Componentアノテーションも導入しており、こちらは他のステレオタイプが論理的に拡張します。アプリケーションの役割を明確に指定することにより、こうしたステレオタイプは、役割に基づいてアノテートされたオブジェクトに追加動作を提供するSpring AOPやポストプロセッサの使用を促進します。たとえば、Spring 2.0はPersistenceExceptionTranslationPostProcessorを導入し、@Repositoryアノテーションを持っているあらゆるオブジェクト向けのデータアクセスの例外翻訳を自動的に有効にしました。

同じアノテーションをSpring 2.5の別の新機能である、クラスパス上のコンポーネント自動検出と連動して使用できます。SpringのメタデータとしてはXMLが伝統的に一番人気のフォーマットですが、唯一の選択肢ではありません。実際、Springコンテナの内部メタデータ表現は純粋なJavaであり、Spring管理オブジェクトの定義にXMLが使われると、定義はインスタンス化プロセスに先駆けてJavaオブジェクトに分析、変換されます。Spring 2.5の重要な新機能の一つに、ソースレベルのアノテーションからそのメタデータの読み取りをサポートしていることがあります。これまでに説明したオートワイヤリング・メカニズムは、依存性注入にアノテーション・メタデータを利用していますが、Spring管理オブジェクトそれぞれの実装クラスを提供するためには、最小限度の「Bean定義」登録が依然として必要です。コンポーネントスキャニング機能を使えば、その最小限度のBean定義をXMLで行う必要さえ無くすことが可能です。

これまでにお見せしたように、Springのアノテーション駆動型オートワイヤリングにより、粒度の細かい制御を犠牲にすることなく、XMLの量をかなり減らすことができます。コンポーネント検出メカニズムは、これをさらに進めます。XMLによるコンフィギュレーションに完全に取って代わる必要はなく、コンポーネントスキャニングはむしろ、XMLメタデータと一緒に動作して全体的なコンフィギュレーションを簡略化できます。XMLとアノテーション駆動型テクニックの組み合わせが可能になったことにより、PetClinicサンプルアプリケーションのバージョン2.5で実際に示したような、バランスのとれたアプローチをもたらすことができます。PetClinicでは、インフラのコンポーネント(データソース、トランザクション・マネジャーなど)と一緒に、外部に置いたプロパティも、説明したとおりにXMLで定義されています。データアクセス階層のオブジェクトも部分的にXMLで定義されていますが、こちらのコンフィギュレーションは@Autowiredアノテーションも活用して依存性注入を簡略化しています。最後に、Web階層「コントローラー」は、全くXMLで定義されていません。その代わり、全Webコントローラーの自動検出は、次のコンフィギュレーションを使ってトリガします。

<context:component-scan base-package="org.springframework.samples.petclinic.web"/> 

「base-package」属性が与えられていることにご注意ください。コンポーネントスキャニングのデフォルトの一致ルールは、そのパッケージ内のクラスについてSpringのあらゆるステレオタイプアノテーションを再帰的に検出します(カンマ区切りのリスト形式で複数のパッケージを用意することも可能)。そのため、PetClinicサンプルアプリケーション向けの様々なコントローラー実装は、@Controllerを使ってアノテートされます(Springの組み込みステレオタイプの一つ)。以下に例を挙げます。

@Controller
public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
...

自動検出コンポーネントは、XMLで定義されたかのようにSpringコンテナに登録されます。上で説明したように、こうしたオブジェクトはその後、アノテーション駆動型オートワイヤリングを活用できます。

コンポーネントスキャナの一致ルールは、タイプやアノテーション、AspectJ表現式、名前パターンの正規表現に基づいて含有もしくは除外するようにフィルタをカスタマイズできます。デフォルトのステレオタイプを無効化することも可能です。たとえば、検査コンフィギュレーションではデフォルトのステレオタイプを無視し、その代わりに、名前がStubで始まる、あるいは@Mockアノテーションを含むあらゆるクラスを自動検出するようにもできます。

<context:component-scan base-package="example" use-default-filters="false">
<context:include-filter type="aspectj" expression="example..Stub*"/>
<context:include-filter type="annotation" expression="example.Mock"/>
</context:component-scan>

タイプ一致の制限を除外フィルタを使って制御することもできます。たとえば、@Repositoryアノテーション以外はデフォルトのフィルタを使う場合は、exclude-filterを追加します。

<context:component-scan base-package="example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

自分だけのカスタムタイプを登録してコンポーネントスキャニングを拡張できる方法が多数存在することは明らかです。ステレオタイプアノテーションは一番シンプルな選択肢で、そのため、ステレオタイプの概念はそれ自体に伸張性があります。以前言及したように、@Componentは、@Repository@Service@Controllerアノテーションが「論理的」に拡張する包括的なステレオタイプインジケーターです。たまたま@Componentはメタアノテーション(すなわち、別のアノテーションに宣言されたアノテーション)としても提供可能であり、@Componentメタアノテーションを有するあらゆるカスタムアノテーションは、スキャナによるデフォルトの一致ルールで自動検出されることになります。例を一つ示せば、耳で聞くよりずっと単純、とおそらく思ってもらえるでしょう。

@PostConstruct@PreDestroyのライフサイクル・アノテーションを扱った項で説明した仮定のバックグラウンドタスクを思い出してください。アプリケーションにはおそらく、そのようなバックグラウンドタスクが多数存在し、そうしたタスク・インスタンスは、Springコンテキストで登録し、適切な時点でライフサイクルメソッドを呼び出すために、一般的にXMLのBean定義を必要とします。コンポーネントスキャニングを使えば、こうした明示的なXMLのBean定義は不要になります。バックグラウンドタスク全てが同一のインターフェースを実装するか、命名規則に従っているのであれば、includeフィルタが使えます。しかし、さらに単純なアプローチは、こうしたタスクオブジェクト向けのアノテーションを作成し、@Componentメタアノテーションを提供することです。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
String value() default "";
}

次に、あらゆるバックグラウンドタスクのクラス定義の中でカスタムのステレオタイプアノテーションを提供します。

@BackgroundTask
public class FilePoller {

@PostConstruct
public void startPolling() {
...
}

@PreDestroy
public void stopPolling() {
...
}
...
}

包括的な@Componentアノテーションはごく簡単に提供できましたが、カスタムアノテーションのテクニックでは、意味のある、ドメイン特異的な名称を使用する機会を提供してくれます。ドメイン特異的なアノテーションは次に、たとえばAspectJのポイントカット表現式を使用して、全バックグラウンドタスクを識別するなどの機会をさらに提供しますが、その目的はこうしたタスクのアクティビティをモニタするアドバイスを追加することです。

コンポーネントが検出されると、Springはデフォルトで、条件を満たしていないクラス名を使用して自動的に「Bean名」を生成します。前の例では、生成されたBean名は「filePoller」となります。しかし、Springのステレオタイプアノテーション(@Component@Repository@Service@Controller)でアノテートされたあらゆるクラス、もしくはメタアノテーション(上の例の@BackgroundTaskなど)として@Componentを使ってアノテートされたその他のあらゆるアノテーションでは、「value」属性がステレオタイプアノテーション向けに明示的に指定されることもあり、その後インスタンスがコンテキスト内で、その値を「Bean名」として登録されることになります。次の例では、名前はデフォルトで生成される名前の「simpleJdbcClinic」ではなく、「petClinic」となります。

@Service("petClinic")
public class SimpleJdbcClinic {
...
}

同様に、FilePollerを修正した以下のバージョンでは、生成されるBean名は「filePoller」ではなく「poller」となります。

@BackgroundTask("poller")
public class FilePoller {
...
}

Spring管理オブジェクトは全て、デフォルトでシングルトンインスタンスとして扱われますが、オブジェクトに代わりの「scope」(スコープ)を明示することも時には必要です。たとえば、Web階層でSpring管理オブジェクトは「request」もしくは「session」scopeに制限されている可能性があります。バージョン2.0では、Springのscopeメカニズムは一様に伸張性があるため、アプリケーション・コンテキストを使ってカスタムscopeを登録できます。XMLコンフィギュレーション内では、「scope」属性とそのscope名を入れればいいだけという簡単さなのです。

<bean id="shoppingCart" class="example.ShoppingCart" scope="session">
...
</bean>

Spring 2.5では、@Scopeアノテーションを提供することにより、同じことをスキャンしたコンポーネントでも実現できます。

@Component
@Scope("session")
public class ShoppingCart {
...
}

ここで最後に扱うべきトピックは、コンポーネントスキャニング使用時の限定子アノテーションの簡略化です。前の項では、カスタム限定子アノテーションを使ったオートワイヤリングの例として次のオブジェクトを使いました。

@VetSpecialty("dentistry")
private Clinic dentistryClinic;

その後同じ例を使って、意図したターゲットBean定義のXML内にある「qualifier」(限定子)要素を、その依存性向けに使用することをお見せしました。コンポーネントスキャニング使用時、XMLメタデータは不要です。その代わり、ターゲットクラス定義内でタイプレベルのアノテーションとしてカスタム限定子を入れてもよいのです。スキャンした@Repositoryインスタンスを依存性として使用した代替例は、次のようになります。

@Repository
@VetSpecialty("dentistry")
public class DentistryClinic implements Clinic {
...
}

最後に、属性を使ってカスタム限定子アノテーションをお見せした前の例では、その依存性ターゲットの非XML同等物は次のようになります。

@Repository
@SpecializedClinic(species="dog", breed="poodle")
public class PoodleClinic implements Clinic {
...
}

結論

Spring 2.5は多数の分野で重要な新しい機能性を提供しています。この記事では主に、Javaアノテーションの能力を利用することによるコンフィギュレーションの簡略化に焦点を当てました。SpringはJSR-250で定義されているとおりの「Common Annotations」(共通アノテーション)をサポートしながら、同時に、オートワイヤリングプロセスのより粒度の細かい制御をするために、追加のアノテーションも提供します。Spring 2.5は、Spring 2.0の@Repositoryから始まった「ステレオタイプ」アノテーションを拡張し、こうしたステレオタイプの全てが、新たなコンポーネントスキャニング機能と連動して使用できます。XMLベースのコンフィギュレーションは依然として完全サポートしていますし、Spring 2.5では、一般的なコンフィギュレーション・シナリオ向けのより簡潔な構文を提供する新しい「context」ネーム空間を導入しました。実際、XMLとアノテーションベースのコンフィギュレーションのシームレスな結合をサポートすることにより、全体的なアプローチがとてもバランス良いものとなりました。インフラの複雑なコンフィギュレーションをモジュラー型XMLファイルで定義できると同時に、徐々にレイヤーが増えていくアプリケーションスタックでは、よりアノテーションをベースにしたテクニックから恩恵を受けることができるでしょう―それも全て、同一のSpring 2.5アプリケーション・コンテキストの中で。

シリーズの第2回をお見逃しなく。次回はSpringのWeb階層内でのアノテーションベースの強力な新機能を取り扱う予定です。

原文はこちらです:http://www.infoq.com/articles/spring-2.5-part-1

この記事に星をつける

おすすめ度
スタイル

BT