webentwicklung-frage-antwort-db.com.de

Bitte erläutern Sie die @Produces-Annotation in CDI

Ich habe über die @Produces-Annotation in CDI gelesen, aber ich kann deren Verwendung nicht verstehen.

public class Resources {

// Expose an entity manager using the resource producer pattern
@SuppressWarnings("unused")
@PersistenceContext
@Produces
private EntityManager em;                                        // 

@Produces
Logger getLogger(InjectionPoint ip) {                            // 
    String category = ip.getMember()
                        .getDeclaringClass()
                        .getName();
    return Logger.getLogger(category);
}

@Produces
FacesContext getFacesContext() {                                 // 
    return FacesContext.getCurrentInstance();
}

}

entnommen aus: http://www.jboss.org/jdf/quickstarts/jboss-as-quickstart/guide/GreeterQuickstart/#GreeterQuickstart-

Wie kann der Container eine Producer-Methode aufrufen? Wenn ich einen EntityManager injiziere, wie ruft der Container den @produces EntityManager auf? Und wie würde eine getLogger-Producer-Methode aufgerufen? 

Ich sehe auch keinen Grund, all die Schwierigkeiten durchzugehen.

38
user798719

Abschnitt 3.3 der CDI-Spezifikation gibt einen ziemlich guten Überblick über die Verwendung der @Produces / -Anmerkung:

Eine Erzeugermethode dient als Quelle für Objekte, die eingefügt werden sollen, wobei:

• Die zu injizierenden Objekte müssen keine Instanzen von Beans oder sein
• Der konkrete Typ der einzubringenden Objekte kann zur Laufzeit variieren oder
• Die Objekte erfordern eine benutzerdefinierte Initialisierung, die nicht vom Bean-Konstruktor ausgeführt wird.

Nehmen wir beispielsweise an, Sie wollten eine Brücke zwischen einer von Java EE verwalteten Komponente wie einem Entitätsmanager und anderen CDI-Komponenten erstellen, Sie könnten die @Produces-Annotation verwenden. Ein weiterer Vorteil besteht darin, dass Sie vermeiden müssen, @PersistenceContext-Anmerkungen in Ihrer Datendomänenschicht zu duplizieren.

class A {
    @PersistenceContext       // This is a JPA annotation
    @Produces                 // This is a CDI 'hook'
    private EntityManager em; 
}

class B {
   @Inject                    // Now we can inject an entity manager
   private EntityManager em;
}

Eine weitere praktische Anwendung ist die Verwendung von Bibliotheken, die keine CDI-fähigen Beans enthalten (z. B. keine Standardkonstruktoren):

class SomeTPLClass {
    public SomeTPLClass(String id) {
    }
}

class SomeTPLClassProducer {
    @Produces
    public SomeTPLClass getInstance() {
        return new SomeTPLClass("");
    }
}

Der Javadoc für Productions zeigt auch einen interessanten (aber ziemlich seltenen) Fall, eine benannte Sammlung zu erzeugen, die später in andere verwaltete Beans injiziert werden kann (sehr cool):

public class Shop { 
    @Produces @ApplicationScoped 
    @Catalog @Named("catalog") 
    private List<Product> products = new LinkedList<Product>(8);

    //...
}

public class OrderProcessor {
    @Inject
    @Catalog
    private List<Product> products;
}

Der Container ist für die Verarbeitung aller mit einer @Produces-Annotation markierten Methoden und Felder verantwortlich und führt dies normalerweise aus, wenn Ihre Anwendung bereitgestellt wird. Die verarbeiteten Methoden und Felder werden dann bei Bedarf als Teil der Injektionspunktauflösung für verwaltete Beans verwendet.

64
Perception

Das Beispiel hat für mich nicht ganz funktioniert. Was für eine Arbeit war ein kleinerer Tweak:

@Alternative
class SomeTPLClass {
    public SomeTPLClass(String id) {
    }
}

class SomeTPLClassProducer {
    @Produces
    public SomeTPLClass getInstance() {
        return new SomeTPLClass("");
    }
}

Also musste ich @Alternative zu meiner Klasse hinzufügen, um den Fehler zu beseitigen, dass zwei Optionen für @Default vorhanden waren.

0
Hans