Istnieje kilka problemów tutaj.
- Jaki jest najlepszy sposób na zmianę pożądanej implementacji w całej aplikacji? Zajrzyj do
@Alternatives
.
- Czy potrzebuję kwalifikatora do każdej realizacji? Nie, odpowiedź na pytanie this można znaleźć w obszernym i szczegółowym wyjaśnieniu.
- Czy powinienem użyć producenta, aby zdecydować, która implementacja zostanie wprowadzona? Może być rozwiązaniem, które chcesz, ale wątpię w to. Producenci są zwykle wykorzystywani do przeprowadzania inicjalizacji, których nie można wykonać w konstruktorze/
@PostConstruct
. Można również użyć go do sprawdzenia punktu wtrysku i podejmowania decyzji czasu wykonywania, co należy wstrzyknąć. Zobacz link 2. dla niektórych wskazówek.
Czy to rozwiązanie jest poprawne? To zadziała, ale nadal będziesz musiał zadzierać z kodem, aby zmienić implementację, więc pomyśl 1. Najpierw. Również @Calculator Calculator
wydaje się bardzo zbędny. Ponownie zobacz link pod adresem 2.
@ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
@Produces @Calculator Calculator getCalculator() {
return new Calculator();
}
}
Aktualizacja:
CDI używa kwalifikatorów oprócz do rodzajów rozwiązywania zależności. Innymi słowy, o ile istnieje tylko jeden typ, który odpowiada typowi punktu wtrysku, wystarczą same typy, a kwalifikatory nie są potrzebne. Kwalifikatory służą do ujednoznacznienia, gdy same typy nie wystarczą.
Na przykład:
public class ImplOne implements MyInterface {
...
}
public class ImplTwo implements MyInterface {
...
}
aby móc wprowadzić zarówno realizację, nie trzeba żadnych kwalifikatorów:
@Inject ImplOne bean;
lub
@Inject ImplTwo bean;
Dlatego mówię @Calculator Calculator
jest zbędny. Jeśli zdefiniujesz kwalifikator dla każdej implementacji, nie zyskujesz zbyt wiele, możesz również użyć tego typu. Powiedzieć, dwie eliminacje @QualOne
i @QualTwo
:
@Inject @QualOne ImplOne bean;
i
@Inject @QualTwo ImplTwo bean;
Przykład bezpośrednio powyżej nic nie zyskać, ponieważ w poprzednim przykładzie nie dis-dwuznaczność już istniał.
Oczywiście, można to zrobić w przypadkach, gdzie nie ma dostępu do poszczególnych rodzajów realizacji:
@Inject @QualOne MyInterface bean; // to inject TypeOne
i
@Inject @QualTwo MyInterface bean; // to inject TypeTwo
jednak PO nie należy używać @Produces kiedy chce, aby kalkulatory były zarządzane CDI.
@Avinash Singh - CDI zarządza @Produces
jak cokolwiek wrócą, tak długo, jak to jest CDI który wywołuje metodę. Jeśli chcesz, zobacz this section of the spec. Obejmuje powrocie `@ ... scoped fasola, które będą wspierać zależnościami callbacków wtrysk, cyklu życia, itp
przeoczyłem pewne szczegóły tutaj, więc należy wziąć pod uwagę następujące dwa:
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;
}
}
}
i
public class SomeProducer {
@Produces
public MyInterface get() {
if (conditionOne()) {
return new ImplOne();
} else if (conditionTwo()) {
return new ImplTwo();
} else {
return new ImplThree;
}
}
}
Następnie, w pierwszym przykładzie, CDI będzie zarządzać cyklem życia (tj. Wsparcie @PostConstruct
i @Inject
) tego, co zostało zwrócone przez producenta, ale w drugim przypadku nie będzie.
Powrót do pierwotnego pytania - jaki jest najlepszy sposób przełączania się między implementacjami bez konieczności modyfikowania źródła? Założeniem jest, że chcesz, aby zmiana miała szeroki zasięg.
@Default
public class ImplOne implements MyInterface {
...
}
@Alternative
public class ImplTwo implements MyInterface {
...
}
@Alternative
public class ImplThree implements MyInterface {
...
}
Następnie każdy z każdym @Inject MyInterface instance
, ImplOne
zostanie wstrzyknięty, chyba
<?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>
jest określona, w którym to przypadku ImplTwo
zostanie wstrzyknięty wszędzie.
Dalsze Aktualizacja
Istnieje rzeczywiście rzeczy w środowisku Java EE, które nie są zarządzane przez CDI, takich jak EJB i usług internetowych.
Jak wstrzyknąć usługę sieci Web do komponentu zarządzanego przez komponent CDI? To naprawdę proste:
@WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
To jest to, tam będziesz mieć ważne odniesienie do usługi płatności, która jest zarządzana poza CDI.
Ale, jeśli nie chcesz korzystać z pełnej wersji @WebServiceRef(lookup="java:app/service/PaymentService")
wszędzie tam, gdzie jej potrzebujesz? Co jeśli chcesz wstrzyknąć tylko według typu? Następnie należy zrobić to gdzieś:
@Produces @WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
aw każdym CDI fasoli, która potrzebuje odniesienie do tej usługi płatniczej można po prostu @Inject
go przy użyciu CDI tak:
@Inject PaymentService paymentService;
Należy pamiętać, że przed określeniem pola producenta , PaymentService
nie byłby dostępny do wstrzyknięcia CDI way. Ale zawsze jest dostępny stary sposób. Ponadto, w obu przypadkach usługa internetowa nie jest zarządzana przez CDI, ale określenie pola producenta po prostu sprawia, że ten odnośnik do usługi sieciowej jest dostępny do wstrzyknięcia metodą CDI.
Proszę zobaczyć moją aktualizację zgodnie z komentarzem. Również producenci i wszystko, co wracają, są zarządzane przez CDI ... – rdcrng
Nie ma powodu do opisywania czegokolwiek z '@ Produces', jeśli zamierzasz to nazwać. – rdcrng
Jak wprowadzić tę usługę do komponentu bean CDI? Użylibyśmy '@Produces @myservice @WebServiceRef (lookup =" java: app/service/PaymentService ") {} @Inject @myservice MyWebService;' W tym przypadku kontener nie zarządza cyklem życia MyWebServiceImpl, jest to po prostu wstrzyknięcie go –