CDI1.1から追加されたbean-discovery-mode

このエントリーは「Java EE Advent Calendar 2013 - Adventar」の5日目のエントリーです。

4日目は@さんの「Standard Caching - CLOVER」でした。
6日目は@さんです。よろしくお願いします。

【前提条件】

[環境]

【概要】

CDI1.1から追加されたbean-discovery-modeについて書きます。

CDI1.0ではbeans.xmlに何も設定を行わない場合、
全てのクラスがインジェクション対象になります。

CDI1.1からはインジェクションの対象を
検索するモードを指定できるようになりました。

【3つのモード】

bean-discovery-modeで指定できるのは
annotated、all、noneの3つです。

[annotated]

CDI1.1のデフォルト値です。
annotatedを指定した場合は
スコープアノテーションを指定してクラスがインジェクション対象となります。

[all]

全てのクラスがインジェクション対象となります。
CDI1.0と同じような動きをします。

[none]

全てのクラスはインジェクション対象外となります。

このモードはJARなどでアーカイブしたときに
インジェクション対象外にしたい時に使うようです。
(たぶん)

サンプルソースについて】

bean-discovery-modeのannotatedとallの動きを試してみます。

JAX-RSのリソースクラスから
オブジェクトをインジェクションさせるサンプルです。

サンプルのソースは↓のような構成です。

SampleInjectionClassクラスがインジェクション対象、
SampleStubクラスはインジェクション対象外にします。
2つのクラスはSampleInterfaceインターフェイスを実装しています。

【前提となるクラス】

[SampleApplication]

JAX-RSのアプリケーションパスを指定しています。

@ApplicationPath("/sample")
public class SampleApplication extends Application {
}
[SampleResource]

SampleResourceクラスから
SampleInterfaceインターフェイスのオブジェクトを
インジェクションしています。

@Path("/annotated")
@RequestScoped
public class SampleResource implements Serializable {

    @Inject
    private SampleInterface injectionObject = null;

    @POST
    public Response executeSample() {
        injectionObject.execute();
        return Response.ok("Method is complete.").build();
    }
}
[SampleInterface]

ただのなんともないインターフェイスです。

public interface SampleInterface {
    void execute();
}

【allモード】

まずはallモードです。

[beans.xml]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
    <scan>
        <exclude name="jp.glory.sample.service.stub.**" />
    </scan>
</beans>

bean-discovery-modeにallを指定します。

タグでインジェクション対象外のクラスを指定します。
name属性にはワイルドカードが使用できます。

サンプルではSampleStubクラスがあるパッケージを
インジェクション対象外として指定します。

[SampleInjectionClass / SampleStub]

インジェクション対象のクラスは
インターフェイスを実装するだけです。

public class SampleStub implements SampleInterface {
    // 何かしらの処理
}
public class SampleInjectionClass implements SampleInterface, Serializable {
    // 何かしらの処理
}

allモードなので全てのクラスがインジェクション対象となりますが、
タグで指定したクラスはインジェクション対象外となります。

【annotatedモード】

続いてannotatedモードです。

[beans.xml]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="annotated">
</beans>

annotatedモードではbean-discovery-mode属性にannotatedを指定するだけです。

[SampleStub]

インジェクション対象外のクラスです。

public class SampleStub implements SampleInterface {
    // 何かしらの処理
}

インジェクション対象外とするクラスには
特に何もアノテーションを指定しません。

[SampleInjectionClass]

インジェクション対象のクラスです。

@SessionScoped
public class SampleInjectionClass implements SampleInterface, Serializable {
    // 何かしらの処理
}

インジェクション対象にするクラスに
スコープアノテーションを付与します。

サンプルではセッションスコープとして
javax.enterprise.context.SessionScopedを付与しています。

スコープアノテーションを指定すると
インジェクション対象のクラスとして認識されます。

【まとめ】

bean-discovery-modeの
annnotated、allをまとめると↓のようになります。

  • annotated
    • インジェクション対象を指定する方式
  • all
    • インジェクション対象外を指定する方式

annotatedだと一つ一つ指定するのでやや面倒くさそうだけど、
意図しないインジェクションが防げそう。

allだと基本的に少ない指定でできるけど、
意図しないインジェクションが紛れ込みそう。

と言うのが個人的な感想です。

私は明示的にやりたいので、annotatedをお勧めしたいです。