SeamFramework.orgCommunity Documentation

Kapitel 6. Producer-Methoden

6.1. Geltungsbereich einer Producer-Methode
6.2. Einspeisung in Producer-Methoden
6.3. Verwendung von @New mit Producer-Methoden

Producer-Methoden gestatten es uns, bestimmte Beschränkungen zu umgehen, die auftreten, wenn der Web Bean Manager statt die Anwendung für die Instantiierung von Objekten verantwortlich ist. Sie sind auch die einfachste Art der Integration von Objekten in die Web Beans Umgebung, die keine Web Beans sind. (In Kapitel 12, Definition von Web Beans unter Verwendung von XML lernen wir eine zweite Weise kennen.)

Gemäß der Spezifikation:

A Web Beans producer method acts as a source of objects to be injected, where:

  • the objects to be injected are not required to be instances of Web Beans,

  • the concrete type of the objects to be injected may vary at runtime or

  • the objects require some custom initialization that is not performed by the Web Bean constructor

For example, producer methods let us:

In particular, producer methods let us use runtime polymorphism with Web Beans. As we've seen, deployment types are a powerful solution to the problem of deployment-time polymorphism. But once the system is deployed, the Web Bean implementation is fixed. A producer method has no such limitation:

@SessionScoped

public class Preferences {
    
    private PaymentStrategyType paymentStrategy;
    
    ...
    
    @Produces @Preferred 
    public PaymentStrategy getPaymentStrategy() {
        switch (paymentStrategy) {
            case CREDIT_CARD: return new CreditCardPaymentStrategy();
            case CHEQUE: return new ChequePaymentStrategy();
            case PAYPAL: return new PayPalPaymentStrategy();
            default: return null;
        } 
    }
    
}

Consider an injection point:

@Preferred PaymentStrategy paymentStrat;

This injection point has the same type and binding annotations as the producer method, so it resolves to the producer method using the usual Web Beans injection rules. The producer method will be called by the Web Bean manager to obtain an instance to service this injection point.

.

Der Geltungsbereich der Producer-Methode ist standardmäßig @Dependent, und daher wird sie jedes Mal aufgerufen, wenn der Web Bean Manager eine Einspeisung in dieses oder ein anderes in diese Producer-Methode auflösendes Feld vornimmt. Es könnten daher mehrere Instanzen des PaymentStrategy-Objekts für jede Benutzer-Session vorhanden sein.

Um dieses Verhalten zu ändern, können wir der Methode eine @SessionScoped-Annotation hinzufügen.

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy() {
    ...
}

Wird jetzt die Producer-Methode aufgerufen, so wird die wiedergegebene PaymentStrategy an den Session-Kontext gebunden. Die Producer-Methode wird in drselben Session nicht mehr aufgerufen.

Es gibt ein potenzielles Problem mit dem Code oben. Die Implementierungen von CreditCardPaymentStrategy werden unter Verwendung des Java new Operators instantiiert. Direkt durch die Anwendung instantiierte Objekte können die Dependency-Einspeisung nicht nutzen und besitzen keine Interzeptoren.

Falls dies nicht das ist was wir wünschen, so können wir Dependency-Einspeisung in die Producer-Methode verwenden, um Web Bean Instanzen zu erhalten:

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
                                          ChequePaymentStrategy cps,
                                          PayPalPaymentStrategy ppps) {
    switch (paymentStrategy) {
        case CREDIT_CARD: return ccps;
        case CHEQUE: return cps;
        case PAYPAL: return ppps;
        default: return null;
    } 
}

Aber Moment mal, was wenn CreditCardPaymentStrategy ein anfragenbegrenztes Web Bean ist? Dann hat die Producer-Methode die Wirkung, dass Sie die aktuelle anfragenbegrenzte Instanz in den Geltungsbereich der Session "befördert". Das ist mit ziemlicher Sicherheit ein Fehler! Das anfragenbegrenzte Objekt wird vom Web Bean Manager gelöscht ehe die Session endet, aber der Verweis auf das Objekt bleibt im Geltungsbereich der Session "hängen" in the session scope. Dieser Fehler wird nicht vom Web Bean Manager aufgespürt, daher seien Sie besonders vorsichtig wenn Sie Web Bean Instanzen von Producer-Methoden wiedergeben!

Es existieren mindestens drei Arten, wie dieser Fehler behoben werden kann. Wir könnten den Geltungsbereich der CreditCardPaymentStrategy-Implementierung ändern, aber das würde auch andere Clients dieses Web Beans betreffen. Eine bessere Option wäre es, den Geltungsbereich der Producer-Methode auf @Dependent oder @RequestScoped zu ändern.

Eine gängigere Lösung ist es jedoch, die spezielle @New Binding-Annotation zu verwenden.

Sehen Sie sich folgende Producer-Methode an:

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
                                          @New ChequePaymentStrategy cps,
                                          @New PayPalPaymentStrategy ppps) {
    switch (paymentStrategy) {
        case CREDIT_CARD: return ccps;
        case CHEQUE: return cps;
        case PAYPAL: return ppps;
        default: return null;
    } 
}

Dann wird eine neue abhängige Instanz von CreditCardPaymentStrategy erstellt, an die Producer-Methode weitergegeben, von der Producer-Methode wiedergegeben und schließlich an den Session-Kontext gebunden. Das abhängige Objekt wird nicht gelöscht bis das Preferences-Objekt gelöscht wird, meist am Ende der Session.