1. Wstęp do CDI
2. Beans
3. Zarządzanie beanami
4. Scopes and context
5. Events
6. Interceptors
7. Decorator
Bean możemy identyfikować n 3 sposoby:
I. Typ
II. Typ i kwalifikator
III. przez nazwę (adnotacja @Named)

I) przez Typ
1. Teraz pokażę przykłady dla konfiguracji beans.xml bean-discovery-mode="all".
Czyli każda klasa jest zarządzana.
Zobaczmy pierwszy przykład:
implementujemy interface:
  1. public interface MyInterface {
  2.         String getIdName();
  3. }
następnie używamy jego implementacji w klasie:
  1. public class MyBean implements MyInterface  {
  2.         public String getIdName() {
  3.                 return "MyBean";
  4.         }
  5. }
i już taką implementację możemy wstrzykiwać używając adnotacji @Inject:
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import javax.enterprise.context.ApplicationScoped;
  4. import javax.inject.Inject;
  5. import javax.inject.Named;
  6.  
  7. @ApplicationScoped
  8. public class MyController {
  9.         @Inject
  10.         private MyBean myBean;
  11.         @Inject
  12.         private MyInterface myInterface;
  13.  
  14.         public String getNameMyInterface() {
  15.                 return myInterface.getIdName(); // wyświetli: "MyBean"
  16.         }
  17.        
  18.         public String getNameMyBean() {
  19.                 return myBean.getIdName(); // wyświetli: "MyBean"
  20.         }
  21. }
Ale gdy np implementujemy drugi raz interface lub dziedziczymy drugi raz
po tej samej klasie będzie błąd, niejednoznaczności wstrzyknięcia.
dodajemy do powyższych klas klasę OtherBean.java:
  1. public class OtherBean extends MyBean {
  2.         public String getIdName() {
  3.                 return "OtherBean";
  4.         }
  5. }
To nam spowoduje błąd deployowania aplikacji, przez co nasza aplikacja nie będzie uruchomiona

Jeden ze sposobów na rozwiązanie tego problemu to ustawienie @Veted na klasie którą nie chcemy mieć zarządzanej przez CDI.
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import javax.enterprise.inject.Vetoed;
  4.  
  5. @Vetoed
  6. public class MyBean implements MyInterface {
  7.         @Override
  8.         public String getIdName() {
  9.                 return "MyBean";
  10.         }
  11. }
  1. public class MyController {
  2.         @Inject
  3.         private MyInterface myInterface;
  4.         @Inject
  5.         private MyBean myBean;
  6.        
  7.         public String getNameMyInterface() {
  8.                 return myInterface.getIdName(); // wypisze: "OtherBean"
  9.         }
  10.        
  11.         public String getNameMyBean() {
  12.                 return myBean.getIdName(); // wypisze: "OtherBean"
  13.         }
  14. }
2.Drugi przykład to implementacja jednego inteface-u przez dwie klasy:
  1. public interface MyInterface {
  2.         String getIdName();
  3. }
  1. public class MyBean implements MyInterface  {
  2.         public String getIdName() {
  3.                 return "MyBean";
  4.         }
  5. }
  1. public class OtherBean implements MyInterface  {
  2.         public String getIdName() {
  3.                 return "OtherBean";
  4.         }
  5. }
I znowu mamy błąd z brakiem jednoznaczności wstrzyknięcia.
Możemy użyć adnotacji @Any na polu Instance<T> przy wstrzyknięciu zależności.
Instance jest to interface który powoduje leniwe wstrzyknięcie beanu
Bean pobieramy używając metody get(). Uzyskujemy w ten sposób dynamicznie aktualną instancję beana.
Instance implementuje on interface iterable<T> przez co możemy użyć pętli forEach.
  1. @Named
  2. @ApplicationScoped
  3. public class MyFirstController {
  4.         @Inject
  5.         @Any
  6.         private Instance<MyInterface> myInterface;
  7.        
  8.         public String getNameFromInterface() {
  9.                 StringBuilder sb = new StringBuilder();
  10.                 for (MyInterface mI : myInterface) {
  11.                         sb.append(mI.getIdName());
  12.                         sb.append(":");
  13.                 }
  14.                 return sb.toString();
  15.         }      
  16. }
Tyle przechodzimy po wszystkich elementach które są Beanem dla danego interface-u.

3. Zobaczmy trzeci sposób na rozwiązanie tego problemu
Aby ten błąd rozwiązać możemy użyć adnotacji @Alternative, wtedy ta klasa będzie
użyta jako alternatywna. @Default będzie w pierwszej kolejności wstrzyknięta.
@Default jest domyślną wartością, nie trzeba jej dodawać, dodanie jej jawnie jest nadmiarowe.
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import javax.enterprise.inject.Alternative;
  4.  
  5. @Alternative
  6. public class MyBean implements MyInterface {
  7.         @Override
  8.         public String getIdName() {
  9.                 return "MyBean";
  10.         }
  11. }
  1. @Named
  2. @ApplicationScoped
  3. public class MyController {
  4.         @Inject
  5.         private MyInterface myInterface;
  6.        
  7.         public String getNameFromInterface() {
  8.                 return myInterface.getIdName(); // wypisane zostanie: "OtherBean"
  9.         }      
  10. }
Ale przypatrzmy się jeszcze interface-owi Instance<>.
Pobiera on aktualną instancję klasy, najbardziej zaktualizowaną.
Mamy klasę:
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import java.text.DateFormat;
  4. import java.text.SimpleDateFormat;
  5. import java.util.Date;
  6.  
  7. public class OtherBean implements MyInterface {
  8.         private String strDate;
  9.         public OtherBean() {
  10.                 DateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss.SSS");  
  11.         strDate = dateFormat.format(new Date());                               
  12.         }
  13.        
  14.         @Override
  15.         public String getIdName() {
  16.                 return strDate;
  17.         }
  18. }
Wstrzykujemy ją do kontrolera:
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import javax.enterprise.context.ApplicationScoped;
  4. import javax.enterprise.inject.Instance;
  5. import javax.inject.Inject;
  6. import javax.inject.Named;
  7.  
  8. @ApplicationScoped
  9. public class MyFirstController {
  10.         @Inject
  11.         private MyInterface myInterface;
  12.         @Inject
  13.         private Instance<MyInterface> myInterfaceInstance;
  14.        
  15.         public String getNameFromInterface() {
  16.                 StringBuilder sb = new StringBuilder();
  17.                 for (int x=0;x<5;x++) {
  18.                         try     {
  19.                             Thread.sleep(1000);
  20.                         }catch(InterruptedException ex) {
  21.                             Thread.currentThread().interrupt();
  22.                         }
  23.                         sb.append(myInterface.getIdName());  // wyświetlone 5x to samo
  24.                         sb.append("<br/>");
  25.                 }
  26.                 return sb.toString();
  27.         }      
  28.        
  29.         public String getNameFromInterfaceInstance() {
  30.                 StringBuilder sb = new StringBuilder();
  31.                 for (int x=0;x<5;x++) {
  32.                         try     {
  33.                             Thread.sleep(1000);
  34.                         }catch(InterruptedException ex) {
  35.                             Thread.currentThread().interrupt();
  36.                         }
  37.                         sb.append(myInterfaceInstance.get().getIdName());  
  38.                         // wyświetlone każdorazowe nowe wartości
  39.                         sb.append("<br/>");
  40.                 }
  41.                 return sb.toString();
  42.         }      
  43. }
i widzimy że pole "myInterface" jest wstrzyknięte tylko przy ładowaniu klasy Kontrolera.
I wyświetlone jest 5x to samo:

2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896

Drugie pole myInterfaceInstance wraz z wywołaniem ".get()", tworzy nową instancje przy
każdym wywołaniu metody ".get()". Instancja jest nowa za każdym razem ponieważ domyślny
zasięg klasy (scope), jest @Dependent.

My Interface Instance:

2020-19-03 01:19:50.902
2020-19-03 01:19:51.903
2020-19-03 01:19:52.903
2020-19-03 01:19:53.904
2020-19-03 01:19:54.904

II) przez Typ i kwalifikator

Wstrzyknięcie może być określone przez kwalifikator (Qualifier).
  1. package pl.edu.java.annotation;
  2.  
  3. import static java.lang.annotation.ElementType.FIELD;
  4. import static java.lang.annotation.ElementType.METHOD;
  5. import static java.lang.annotation.ElementType.PARAMETER;
  6. import static java.lang.annotation.ElementType.TYPE;
  7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  8.  
  9. import java.lang.annotation.Retention;
  10. import java.lang.annotation.Target;
  11.  
  12. import javax.inject.Qualifier;
  13.  
  14. @Qualifier
  15. @Retention(RUNTIME)
  16. @Target({TYPE, METHOD, FIELD, PARAMETER})
  17. public @interface QMainBean {}
  18.  
Dostępne wartości dla adnotacji Retention dla Java 11 pod linkem:
docs.oracle.com/../RetentionPolicy.html
Możliwe wartości dla adnotacji target dla Java 11 pod linkem:
docs.oracle.com/../ElementType.html
  1. public interface MyInterface {
  2.         String getIdName();
  3. }
  1. public class MyBean implements MyInterface  {
  2.         public String getIdName() {
  3.                 return "MyBean";
  4.         }
  5. }
  1. @QMainBean
  2. public class OtherBean implements MyInterface  {
  3.         public String getIdName() {
  4.                 return "OtherBean";
  5.         }
  6. }
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import javax.enterprise.context.ApplicationScoped;
  4. import javax.inject.Inject;
  5.  
  6. @ApplicationScoped
  7. public class MyFirstController {
  8.         @Inject
  9.         @QMainBean
  10.         private MyInterface myInterface;
  11.        
  12.         public String getNameFromInterface() {
  13.                 return myInterface.getIdName(); // wypisne: "OtherBean"
  14.         }      
  15. }
III) przez nazwę (adnotacja @Named)
  1. public interface MyInterface {
  2.         String getIdName();
  3. }
  1. public class MyBean implements MyInterface  {
  2.         public String getIdName() {
  3.                 return "MyBean";
  4.         }
  5. }
  1. @Named("otherBean")
  2. public class OtherBean implements MyInterface  {
  3.         public String getIdName() {
  4.                 return "OtherBean";
  5.         }
  6. }
  1. package pl.edu.java.cdi.managedBeans;
  2.  
  3. import javax.enterprise.context.ApplicationScoped;
  4. import javax.inject.Inject;
  5. import javax.inject.Named;
  6.  
  7. @Named
  8. @ApplicationScoped
  9. public class MyFirstController {
  10.         @Inject
  11.         @Named("otherBean")
  12.         private MyInterface mysInterface;
  13.        
  14.         public String getNameFromInterface() {
  15.                 return myInterface.getIdName(); // wypisne: "OtherBean"
  16.         }      
  17. }
Adnotacja @Named ma specjalną funkcję. W komponentach JSF używane są tylko Kwalifikatory @Named,
tak identyfikujemy beany dla komponentów JSF. i tym sposobem aby połączyć się do klasy kontrolera:
MyFirstController, używamy wyrażenia EL, i możemy dostać się do niego za pomocą:
<h:outputText value="#{myFirstController.getNameFromInterface()}" />
created by cv.java.org.pl © 2023 All Rights Reserved.