プロデューサはオブジェクトを動的にインジェクトさせる仕組みである。 通常@Injectアノテーションを使った場合、インジェクトされるオブジェクトは1つに特定される。 しかし、@Producesを付与したプロデューサメソッドを作成することによりインジェクト対象のオブジェクトを動的に変更させることができる。
簡単なサンプルを使って説明する。
サンプルのための管理ビーンを作成する。通常の手順で作成し、特別なことは何もしない。
package producer;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
/** 管理Beanクラス */
@Named
@RequestScoped
public class ProducerTestBean implements Serializable{
/** シリアルバージョンUID */
private static final long serialVersionUID = 1L;
/** ロジッククラス */
@Inject
private TestLogic logic;
/** イベントメソッド */
public void send(){
logic.execute();
}
}
ProducerTestBeanクラスがインジェクトするクラスを作成する。 TestLogicとTestLogicを継承したTestLogic2の2つのロジッククラスを作成。 通常インジェクトされるクラスにはスコープアノテーションをつけるが、ここでは何も付与しない。 次に作成するプロデューサクラスで、この2つのクラスを動的にインジェクトさせる。
package producer;
/** ロジッククラス */
public class TestLogic{
/** メソッド */
public void execute(){
System.out.println("TestLogic execute");
}
}
TestLogic2.java
package producer;
/** ロジッククラス */
public class TestLogic2 extends TestLogic{
/** メソッド */
public void execute(){
System.out.println("TestLogic2 execute");
}
}
プロデューサクラスを作成する。 インジェクト対象オブジェクトを返却するプロデューサメソッドを1つ定義する。
package producer;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
/** ロジッククラスプロデューサ */
@Dependent
public class TestLogicProducer{
/** ロジッククラス取得 */
@Produces
@Dependent
public TestLogic getTestLogic(InjectionPoint ip){
// Injectしているクラス名を取得
String className = ip.getMember().getDeclaringClass().getName();
TestLogic testLogic;
if(className.equals("producer.ProducerTestBean")){
// TestLogic2を生成
testLogic = new TestLogic2();
}else{
// TestLogicを生成
testLogic = new TestLogic();
}
// ロジッククラスを返却
return testLogic;
}
}
①クラス宣言
@Dependent
public class TestLogicProducer{
@RequestScopedや@ApplicationScopedなどスコープアノテーションを付与する。 今回は@Dependentにしている。
②メソッド宣言
@Produces
@Dependent
public TestLogic getTestLogic(InjectionPoint ip){
インジェクト対象のオブジェクトを返却するメソッドを定義する。
メソッド宣言の上部に@Producesを付与する。これにより、戻り値の型をインジェクト(@Inject)している箇所が存在すると、本メソッドの戻り値をインジェクトしてくれる。
またスコープアノテーションを付与することで、戻り値のオブジェクトの生存期間を指定できる。今回は@Dependentを付与しているため、インジェクト元のオブジェクトと同期間になる。
@Dependentを指定するとメソッドの引数でInjectionPointクラスが取得できる。 このクラスにはインジェクト元の情報が格納されている。InjectionPoint#getMember()でインジェクト元のクラスや@Injectが付与されている変数の情報などを取得できる。 例えば、System.out.println(ip)とすると以下が出力される。
[BackedAnnotatedField] @Inject private producer.ProducerTestBean.logic
また以下のようにするとインジェクト元のクラス名(producer.ProducerTestBean)が取得できる。
ip.getMember().getDeclaringClass().getName()
前述したように@Dependentでない場合、InjectionPointは取得できない。メソッドの引数にInjectionPointを指定しているとサーバ起動時に以下のエラーが発生する。
Exception while loading the app : CDI definition failure:WELD-001406: Cannot inject [BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedMethod] @Produces @RequestScoped public producer.TestLogicProducer.getTestLogic(InjectionPoint) in a non @Dependent scoped bean
③条件によって、異なるロジッククラスを生成して返却
TestLogic testLogic;
if(className.equals("producer.ProducerTestBean")){
// TestLogic2を生成
testLogic = new TestLogic2();
}else{
// TestLogicを生成
testLogic = new TestLogic();
}
// ロジッククラスを返却
return testLogic;
今回はインジェクト元のクラス名によって返却するロジッククラスを変更するように分岐させた。 サンプルではインジェクト元はProducerTestBeanの1クラスしかないが、複数存在した場合は、インジェクト元がproducer.ProducerTestBeanだったらTestLogic2、それ以外だったらTestLogicを返却するようになっている。
これでProducerTestBeanのlogic変数に戻り値(TestLogic2)がインジェクトされ、logic.execute()ではTestLogic2#execute()が実行される。