CDI: Nutzung von Referenzen

miketech

Bekanntes Mitglied
Hallo zusammen,

ich habe folgendes Szenario:

Ich habe eine Bean (Session Scoped) A. Diese Bean A erstellt eine Instanz einer Klasse, die das Interface B implementiert, mittels einer Factory.


Code:
@Named
@RequestScoped
public class A() {


  public void doSomething() {
     B b = MyFactory.createB();
     b.doSomthingElse();
  }

}

Nun habe ich das Problem, dass ich von B heraus eigentlich eine Methode aus A aufrufen müsste. Wie gehe ich nun vor? Soll ich die aktuelle Instanz von A als Parameter übergeben? Oder ist das hässlich, wenn ich eigentlich mit CDI arbeite?

Code:
@Named
@RequestScoped
public class A() {


  public void doSomething() {
     B b = MyFactory.createB(this);
     b.doSomthingElse();
  }

}

Allerdings erstellt MyFactory ja nur eine Instanz einer Klasse, die B implementiert und von diesen Klassen habe ich ca. 15 verschiedene. Ist es hier dann üblich, dennoch mit bspw. RequestScoped Beans für jede dieser 15 verschiedenen zu arbeiten? Wäre ja durchaus möglich, dass ich dann jeweils eine Instanz mittels CDI zurückliefere.

Was ist denn hier BestPractice?

Danke

Mike
 

miketech

Bekanntes Mitglied
Hi,

danke für deine Antwort. Mit A mache ich das ja. Aber bei B gibt es zig verschiedene Varianten, wo ich abhängig von verschiedenen Parametern eine andere Variante benötige. Es wäre schon möglich in der Factory zu sagen:

Code:
public class MyFactory {
  public static B create() {
    if .... 
     return @Inject B1;
    else 
     return @Inject B2;
  }
}

public class B {
  private @Inject A a;
}

Weiß nicht, ob das syntaktisch so möglich ist bei dem return. Aber ich habe so etwas meine Bedenken, dass ich den RequestScope nicht immer einhalte. Vielleicht benötige ich zwei verschiedene B1 in einem Request. Ich weiß nicht, ob ich dann nicht aus Versehen auf derselben Instanz arbeite, obwohl ich eigentlich zwei verschiedene bräuchte.

Gruß

Mike
 

TheDoctor

Mitglied
Zunächst würde ich grundlegend nochmal über die Architektur nachdenken. Statische Factories sind wahnsinnig schlecht mit Blick auf Testbarkeit da sowas quasi nicht weg zu mocken ist.

Ohne Garantie auf Richtigkeit weil ich selbst kein CDI Pro bin würde ich aber folgendes versuchen. Ich würde mir für alle deine Implementierungen von B entsprechende Qualifier erstellen und dann direkt aus Klasse A die entsprechende Implementierung über Instance injizieren
Code:
 @Inject @Bimpl1 
    private Instance<B> Bimpl1;

    @Inject @Bimpl2 
    private Instance<B> Bimpl2;

    @Inject @Bdefault 
    private Instance<B> Bdefault;
        
    private B b;

    protected void AMethode() {
        if (Bdefault = true) {
            b = Bdefault.get();
        } else if (!Bimpl1 = true) {
            b = Bimpl1.get();
           ........
        }
Wobei auch Field Injection eigentlich nicht so günstig ist. Ich tendiere immer dazu alles im Konstruktor oder an der Methode wo ich es nutze zu injizieren.

Um nun von B auf A zugreifen zu können und keine zirkuläre Abhängigkeit zu bekommen würde ich dann entsprechend in B eine lazy Injection machen:

Code:
@Inject
    Instance<A> aInstance;

    public A getA()
    {
        return aInstance.get();
    }
 

FArt

Top Contributor
Ich würde mich auch mal fragen, warum B eine Methode von A aufrufen muss, also was dieses Konstrukt realisieren soll. Evtl. gibt es da eine bessere Lösung.
 

Landei

Top Contributor
Wenn es wirklich so schwierig ist, das aktuell "richtige" B herauszufinden, brauchst du einen entsprechenden Dienst dafür, und den kannst du dir dann injizieren lassen.
 

miketech

Bekanntes Mitglied
Hallo zusammen,

danke für Eure Antworten. Ich werde dann tatsächlich noch einmal umdenken. Das ist dann irgendwie noch nicht ideal von der Architektur. Ich werde versuchen, wirklich komplett auf CDI Beans zu setzen, weil dann muss ich diese Referenzen nicht mitschleifen. Das ist nur, weil ich sonst von einer normalen (nicht CDI) Bean nicht mehr auf die CDI Bean zugreifen kann.

Gruß

Mike
 

Neue Themen


Oben