3.9. Annotation-based container configuration

概要

大まかにサポートするアノテーションは以下のとおり

  • @Required
  • @Autowired
  • JSR-250(@Resources,@PostConstruct)
  • JSR-330(@Inject,@Qualifier,@Named,@Provider) → CDIですね。

これらのアノテーションを使うためには、対応するBeanPostProcessorが登録されている必要がある。
なお設定ファイルによるインジェクションの前にアノテーションによるインジェクションが行なわれるので、設定ファイルのほうが優先される。(試したら実際そうなった)

アノテーションを使う場合はxmlにこう書く。


<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
">http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config/>
</beans>

こうすると、BeanPostProcessorにAutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessorが登録される。
なおを書くと、これを定義したコンテナ(アプリケーションコンテキスト)だけ検索対象となる。よって、例えばWebApplicationContextにを設定した場合、@Autowiredをつけたコントローラクラスは評価されるが、サービスクラスは評価されないよ。

3.9.1 @Required

setterインジェクションに対してインジェクション必須であることを表すアノテーション。setterメソッドに定義すると、beanが設定されていない場合は初期化時にエラーになる。以下推測だけどsetterにしか定義できないのは、この機能がxmlでのインジェクションを想定しているから。で、オートワイアリングするときはそもそもこんなの付けなくてもエラーになるので問題ない。と思う。

3.9.2 @Autowired and @Inject

@Autowiredと@Injectの違い:

  • @Autowiredはrequired属性で任意であることを指定できる。
  • @Injectはその機能ないけどJSR-330準拠。

@Autowiredは、メソッド・属性・コンストラクタに定義できる。配列やコレクションに付けると、その型を実装するすべてのBeanがインジェクションされる。Mapの場合はbean名をキーにして全て設定される。なおBeanFactory, ApplicationContext, ResourceLoader, ApplicationEventPublisher, MessageSourceなどのSpringが提供するインタフェースは、特にBeanが定義しなくても@Autowiredでインジェクションできる。

3.9.3 Fine-tuning annotation-based autowiring with qualifiers

@Qualifierについて
デフォルトの@Autowiredは、型による(byTypeな)インジェクションなのでいろいろ問題がある。これを避けるための方法として、「Springの」@Qualifierが利用可能。(なおCDIの@Qualifierはメタアノテーション。名前が一緒なので注意。)

要するに名前を与えるわけだが、この名前はbean名やidとは違う。異なる型であれば名前がかぶっていても良い(!)(ちなみにBeanに@Qualifierを付けなかった場合はbean名がデフォルトのQualifierになります)

例:


@Qualifier("KoshaALogic")
public class KoshaALogicImpl implements BankLogic{

@Qualifier("KoshaBLogic")
public class KoshaBLogicImpl implements BankLogic{

として


public class Client{

@Qualifier("KoshaBLogic")
private BankLogic bankLogic;

とやると、BankLogicを実装するクラスの中から、Qualifierが一致するものを検索する。つまりまず型で絞り込むわけなので、全体で一意でなくても良いわけです。これは結構使えると思う。一意でなくてもよいので、セマンティクスで分類できるのがヨサゲだ。ちなみに同じ型に対して同じQualifierをわり当てることもできる。この場合はコレクションに@Qualifierを指定すると、@Qualifierが同じBeanが全て設定される。

なお、もしbean名(ID)で識別したい場合はQualifierではなくJSR-250の@Resourceを使ったほうが良い。意味的に@ResuoruceはIDで参照することができるから。また、BeanそのものがMapだったりするようなものは@Autowiredでインジェクション出来ません。事前に型解決ができないからです。この場合も@Resource使いましょう

@Qualifierをメタアノテーションとして使うことで、インジェクションのための独自アノテーションを作成できる。


@Target({ElementType.FIELD, ElementType.PARAMETER,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MyAnnotation {
String value();

これを使うと、カスタムアノテーションでマークしたBeanのインジェクションは、同じアノテーションを使わないとインジェクションできない。例えば


@Component
@MyAnnotation("hoge")
class Hoge

をインジェクションするには


@MyAnnotaiton("hoge")
private Hoge hoge;

としなければならず、


@Qualifier("hoge")
private Hoge hoge;

ではだめということです、使えるかもね。

ちなみに上記をxmlで定義する場合はこうします。


<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>

当たり前だけど無名にもできる。カスタムアノテーションの用途的にはこっちのが良いと思う。

またカスタムアノテーションにname以外の属性を定義することもできる。ENUMとかも定義できて、これ使ってインジェクションするBeanを指定できる。


@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre();
Format format();
}


@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;

みたいな。

3.9.4 CustomAutowireConfigurer

@Qualifierを使わずに、独自のカスタムアノテーションを登録するBeanPostProcessorですよ。


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

3.9.5 @Resource

JSR-250 @Resource annotationによるインジェクションができます。

@Resource("hoge")とすると、bean名がhogeを引っ掛ける。@Resource()とすると、byTypeな検索ではなく、属性名をbean名として使用して引っ掛ける(注意!!)。このとき一致するものがなければ、型で検索してprimaryがついたBeanを指します。なお、@Injectなどと同じように、BeanFactory, ApplicationContext, ResourceLoader, ApplicationEventPublisher, MessageSource をBeanの定義なく指すこともできます。

3.9.6 @PostConstruct and @PreDestroy

initialization callbacksと destruction callbacksのアノテーション版でございます。