Warum empfiehlt Grails den Singleton-Bereich für Controller mit Aktionen als Methoden?

7

Ich weiß, dass frühe Versionen von Grails den Prototypbereich für Controller verwendeten, weil Aktionen zu dieser Zeit alle Schließungen waren.

Ich weiß, dass die aktuelle Version Dokumentation Singleton scoped Controller für Controller empfiehlt, die Methoden als Aktionen verwenden.

Aus dem folgenden Beitrag scheint es, dass Methoden und Singleton-Bereich wünschenswerter oder empfohlen sind, aber es ist nicht klar, warum.
ttp: //grails.1312388.n4.nabble.com /Default-scope-for-controllers-doc-td4657986.html

Wir haben ein großes Projekt, das prototypische Controller mit Aktionen als Methoden verwendet. Das Wechseln zum empfohlenen Controller-Umfang beinhaltet Risiken und erneute Tests und das Entfernen aller nicht Singleton-freundlichen Zustände von vorhandenen Controllern.

Ich würde gerne wissen Warum empfiehlt Grails Singleton Scope für Methoden als Action Controller? Liegt es nur daran, dass Spring MVC häufiger und ähnlicher ist und Verwirrung vermieden wird oder gibt es eine Möglichkeit zur Leistungsverbesserung oder was? Was kann ich gewinnen, wenn ich auf Singleton-Controller umschalte? Was kostet es, wenn ich den Switch nicht aktiviere?

    
DAC 16.04.2015, 18:04
quelle

1 Antwort

20

Ich habe nicht viel mit Rails gearbeitet, aber (zumindest in den Versionen, mit denen ich gespielt habe, können die Dinge jetzt anders sein), der Controller ist das Modell, das die Daten enthält, die von der Ansicht wiedergegeben werden sollen. Während der Verarbeitung von Anforderungen speichern Sie Werte in Controller-Instanzfeldern, bevor Sie die Verarbeitung zum Anzeigen von Renderern übergeben. Daher ist es sinnvoll, für jede Anforderung eine neue Controller-Instanz zu erstellen, damit sie eindeutig sind.

Grails wurde von Rails inspiriert und verwendet einige seiner Konventionen, am bekanntesten Convention-over-Configuration. Aber die Fähigkeit, den Controller als das Modell zu verwenden, wurde auch als ein Feature hinzugefügt, obwohl es nicht gut dokumentiert war und ich bezweifle, dass es von vielen benutzt wurde.

Der typische Weg, wie eine Controller-Aktion funktioniert, wenn ein GSP die Antwort (im Gegensatz zum Weiterleiten oder Weiterleiten oder direkt im Controller, zB mit render foo as JSON ) darstellt, ist das Zurückgeben einer Map mit einem oder mehreren Schlüsseln / Wertepaare aus der Aktion, und oft wird das return -Schlüsselwort weggelassen, da es in Groovy optional ist:

%Vor%

Hier hat die Modellzuordnung zwei Einträge, einen mit user und den anderen mit other und die Variablennamen, die im GSP für den Zugriff auf die Daten verwendet werden.

Aber was die meisten Leute nicht wissen ist, dass Sie es auch so machen könnten:

%Vor%

In diesem Fall wird keine Modellzuordnung von der Aktion zurückgegeben, daher würde Grails das Modell aus allen Eigenschaften der Controller-Klasse auffüllen, und in diesem Fall würde das gleiche GSP für beide Ansätze funktionieren, da die Variablennamen in der zweiten Ansatz sind die gleichen wie die Kartenschlüssel in der ersten.

Die Option, Controller-Singletons zu erstellen, wurde in 2.0 hinzugefügt (technisch 1.4, bevor sie in 2.0 umbenannt wurde, siehe dieses JIRA-Problem <) (a)) und wir haben auch Unterstützung für Methoden als Maßnahmen hinzugefügt, zusätzlich zur Beibehaltung von Schließungen. Die ursprüngliche Annahme war, dass die Verwendung von Schließungen einige interessante Merkmale ermöglichen würde, aber das ist nie passiert. Die Verwendung von Methoden ist natürlicher, da Sie sie in Unterklassen überschreiben können, im Gegensatz zu Schließungen, bei denen es sich nur um Klassenbereichsfelder handelt.

Als Teil der 2.0-Überarbeitung haben wir das von Rails inspirierte Feature entfernt, da es im Prinzip undokumentiert ist, dass die Auswirkungen auf die wenigen Apps, die dieses Feature nutzen, nicht signifikant sind. Ich kann mich nicht erinnern, dass sich jemals jemand über den Verlust dieses Features beschwert hat.

Obwohl Controller-Klassen in der Regel ohne großen Aufwand gesammelt werden können und die Erstellung einer Instanz pro Anfrage keinen großen Einfluss hat, ist es in einem Controller selten erforderlich, einen Status per Request zu verlangen, daher sind Singletons normalerweise sinnvoller. Der Standard-Prototypbereich wurde aus Gründen der Abwärtskompatibilität beibehalten, aber es ist einfach, den Standardwert mit einer Config.groovy-Eigenschaft zu ändern (und die vom create-app -Skript generierte Datei dies tut).

Obwohl jede Anfrage eine neue Anfrage und Antwort erhält, und wenn Sitzungen verwendet werden, hat jeder Benutzer seine eigenen, aber das sind keine Instanzfelder der Controller. Sie sehen aus wie sie sind, weil wir auf request , response , session , params usw. innerhalb von Aktionen zugreifen können, aber das sind eigentlich die Zugriffsformen für die Eigenschaften von getRequest() , getResponse() ,% Methoden co_de% und getSession() , die bei der Kompilierung durch AST-Transformationen in alle Controller gemischt werden. Die Methoden greifen auf ihre Objekte nicht als Klassenfelder, sondern über ThreadLocals zu, so gibt es pro Request-Status, aber es ist nicht in der Controller-Instanz gespeichert.

Ich kann mich nicht erinnern, ob es im Benchmarking viel zu vergleichen gab, wenn man Methoden mit Schließungen verglichen hat, aber Lari Hotari hat wahrscheinlich einiges getan. Wenn es einen Unterschied gab, war es wahrscheinlich nicht signifikant. Sie können dies in Ihrer eigenen Anwendung testen, indem Sie nur einen oder wenige Controller konvertieren und vor und nach den Tests arbeiten. Wenn die Leistungsunterschiede, die Skalierung und die Speicherunterschiede zwischen den beiden Ansätzen nicht signifikant sind, können Sie sicher sein, dass Sie mit dem Prototyp Score und / oder Closures bleiben. Wenn es einen Unterschied gibt und Sie keine Instanzfelder in Ihren Controllern haben, wird es sich wahrscheinlich lohnen, auf Singletons und Methoden umzustellen.

Wenn Sie Instanzfelder haben, können Sie diese wahrscheinlich in Anforderungsattribute konvertieren - getParams() ist eine Metaklassenverknüpfung für request.foo = 42 , so dass Sie stattdessen pro-Anfrage-Daten sicher dort speichern können.

    
Burt Beckwith 16.04.2015, 22:57
quelle