ここにはいくつかの問題があります。
- アプリケーション全体で目的の実装を変更する最善の方法は何ですか? を調べ
@Alternatives
ます。
- 実装ごとに修飾子が必要ですか? いいえ、長くて詳細な説明については、この回答を参照してください。
- プロデューサーを使用して、どの実装を挿入するかを決定する必要がありますか? あなたが望む解決策かもしれませんが、私はそれを疑っています。プロデューサーは通常、コンストラクター / では実行できないある種の初期化を実行するために使用されます
@PostConstruct
。また、インジェクション ポイントを検査し、何をインジェクトするかを実行時に決定するために使用することもできます。いくつかの手がかりについては、リンク 2. を参照してください。
この解決策は正しいですか?これは機能しますが、実装を変更するにはコードをいじる必要があるため、最初に 1. を検討してください。また@Calculator Calculator
、冗長性が高いようです。もう一度、2 のリンクを参照してください。
@ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
@Produces @Calculator Calculator getCalculator() {
return new Calculator();
}
}
アップデート:
CDI は、依存関係の解決に型に加えて修飾子を使用します。つまり、注入ポイントの型と一致する型が 1 つしかない場合は、型だけで十分であり、修飾子は必要ありません。修飾子は、型だけでは不十分な場合に曖昧さをなくすためにあります。
例えば:
public class ImplOne implements MyInterface {
...
}
public class ImplTwo implements MyInterface {
...
}
どちらの実装も注入できるようにするために、修飾子は必要ありません。
@Inject ImplOne bean;
また
@Inject ImplTwo bean;
だから@Calculator Calculator
冗長だと言っているのです。実装ごとに修飾子を定義しても、多くは得られず、単に型を使用した方がよいでしょう。たとえば、2 つの修飾子@QualOne
と@QualTwo
:
@Inject @QualOne ImplOne bean;
と
@Inject @QualTwo ImplTwo bean;
前の例ではあいまいさの解消がまだ存在していないため、すぐ上の例では何も得られません。
確かに、特定の実装タイプにアクセスできない場合は、これを行うことができます。
@Inject @QualOne MyInterface bean; // to inject TypeOne
と
@Inject @QualTwo MyInterface bean; // to inject TypeTwo
ただし、電卓の実装をCDIで管理したい場合、OPは@Producesを使用すべきではありません。
@Avinash Singh -@Produces
メソッドを呼び出すのが CDI である限り、CDI はそれらが返すものと同様に管理します。よろしければ、仕様のこのセクションを参照してください。これには、依存性注入、ライフサイクル コールバックなどをサポートする `@...Scoped Bean を返すことが含まれます。
ここではいくつかの詳細を見落としているため、次の 2 つを考慮してください。
public class SomeProducer {
@Inject ImplOne implOne;
@Inject ImplTwo implTwo;
@Inject ImplThree implThree;
@Produces
public MyInterface get() {
if (conditionOne()) {
return implOne;
} else if (conditionTwo()) {
return implTwo;
} else {
return implThree;
}
}
}
と
public class SomeProducer {
@Produces
public MyInterface get() {
if (conditionOne()) {
return new ImplOne();
} else if (conditionTwo()) {
return new ImplTwo();
} else {
return new ImplThree;
}
}
}
次に、最初の例では、CDI はプロデューサから返されたもののライフ サイクル (つまり@PostConstruct
、@Inject
サポート) を管理しますが、2 番目の例では管理しません。
元の質問に戻る - ソースを変更せずに実装を切り替える最良の方法は何ですか? 前提として、変更をアプリケーション全体に適用する必要があります。
@Default
public class ImplOne implements MyInterface {
...
}
@Alternative
public class ImplTwo implements MyInterface {
...
}
@Alternative
public class ImplThree implements MyInterface {
...
}
次に、 any for anyが注入されます@Inject MyInterface instance
。ImplOne
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>ImplTwo</class>
</alternatives>
</beans>
が指定されている場合、ImplTwo
どこにでも注入されます。
更なるアップデート
Java EE 環境には、EJB や Web サービスなど、CDI によって管理されないものがあります。
Web サービスを CDI マネージド Bean にどのように注入しますか? 本当に簡単です:
@WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
以上で、CDI の外部で管理される支払いサービスへの有効な参照が得られます。
しかし、必要な場所でフルを使用したくない場合はどうすれば@WebServiceRef(lookup="java:app/service/PaymentService")
よいでしょうか? 型だけで注入したい場合はどうしますか?次に、これをどこかで行います:
@Produces @WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
その支払いサービスへの参照が必要な CDI Bean では、次のように CDI@Inject
を使用して簡単に参照できます。
@Inject PaymentService paymentService;
プロデューサー フィールドを定義する前は、 CDI の方法PaymentService
で注入できないことに注意してください。しかし、それは常に古い方法で利用できます。また、いずれの場合も Web サービスは CDI によって管理されませんが、プロデューサー フィールドを定義することで、その Web サービス参照が CDI の方法で注入できるようになります。