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:

Eine Web Beans Producer-Methode fungiert als Quelle einzuspeisender Objekte wenn:

  • die einzuspeisenden Objekte keine Instanzen von Web Beans sein müssen,

  • der konkrete Typ einzuspeisender Objekte zur Runtime variieren kann oder

  • die Objekte eine bestimmte angepasste Initialisierung erfordern, die nicht vom Web Bean Konstruktor durchgeführt wird

Producer-Methoden lassen uns zum Beispiel:

Insbesondere lassen uns Producer-Methoden Runtime-Polymorphie mit Web Beans verwenden. Wie wir bereits gesehen haben sind Deployment-Typen eine leistungsfähige Lösung zum Problem der Polymorphie zum Zeitpunkt des Deployment. Aber nachdem das System deployt ist, wird die Web Bean Implementierung behoben. Eine Producer-Methode besitzt keine solche Einschränkung:

@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;
        } 
    }
    
}

Überlegen Sie einen Einspeisungspunkt:

@Preferred PaymentStrategy paymentStrat;

Dieser Einspeisungspunkt besitzt denselben Typ und diesselben Binding-Annotationen wie die Producer-Methode, so dass er unter Verwendung der üblichen Web Beans Einspeisungsregeln zur Producer-Methode auflöst. Die Producer-Methode wird vom Web Bean Manager aufgerufen um eine Instanz zu erhalten, um diesen Einspeisungspunkt zu bedienen.

.

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.