Heim >Web-Frontend >js-Tutorial >Detaillierte Einführung in Avalonjs

Detaillierte Einführung in Avalonjs

怪我咯
怪我咯Original
2017-06-27 11:46:421951Durchsuche

Eine kurze Geschichte von Avalon und ein Überblick über alle Designprinzipien, die es geschaffen haben
Alles begann mit dem Apache JServ-Projekt. Stefano Mazzocchi und andere, die bei der Entwicklung von Apache JServ mitgewirkt haben, erkannten, dass einige der im Projekt verwendeten Muster allgemein genug waren, um zur Erstellung eines Server-Frameworks verwendet zu werden. Am Mittwoch, dem 27. Januar 1999 (ungefähr einen Monat nach der Veröffentlichung von JServ 1.0b), machte Stefano einen Vorschlag, ein Projekt namens Java Apache Server Framework zu starten. Sein Ziel ist es, die Grundlage für den gesamten Java-Servercode bei Apache zu werden. Die Idee besteht darin, einige Komponenten zu zentralisieren und Code projektübergreifend wiederzuverwenden, indem ein Framework bereitgestellt wird.
Stefano Mazzocchi, Federico Barbieri und Pierpaolo Fumagalli haben die Originalversion erstellt. Ende 2000 schlossen sich Berin Loritsch und Peter Donald dem Projekt an. Zu diesem Zeitpunkt hatten Pierpaolo und Stefano sich der Entwicklung anderer Projekte zugewandt und das Java Apache Server Framework erhielt den Namen Avalon. Diese fünf Entwickler sind in erster Linie für das Design und die Konzepte verantwortlich, die in der aktuellen Version des Frameworks verwendet werden. Die aktuelle Version ist der im Juni 2000 veröffentlichten Version sehr ähnlich. Tatsächlich besteht der Hauptunterschied in der Neuorganisation von Paketen und der Aufteilung von Projekten in Teilprojekte. Die gleichen Designmuster und Schnittstellen existieren auch heute noch.

Was ist Avalon?
Avalon ist das übergeordnete Projekt von fünf Unterprojekten: Framework, Excalibur, LogKit, Phoenix und Cornerstone. Wenn sie Avalon hören, denken die meisten Leute an Framework, aber Avalon umfasst mehr als nur Framework. Avalon begann als Java Apache Server Framework, bestehend aus dem Framework, Tools, Komponenten und einer Server-Core-Implementierung, alles in einem Projekt. Da verschiedene Teile von Avalon unterschiedliche Reifegrade und unterschiedliche Veröffentlichungszyklen aufweisen, haben wir uns entschieden, Avalon in die zuvor erwähnten kleinen Projekte zu unterteilen. Dadurch wird es auch für neue Entwickler einfacher, die verschiedenen Teile von Avalon zu verstehen und zu erlernen – etwas, das vorher fast unmöglich war. Framework
Avalon Framework ist die Grundlage für alle anderen Projekte unter dem Avalon-Dach. Es definiert die Schnittstellen, Verträge und die Standardimplementierung von Avalon. Framework steckt die meiste Arbeit darin, es ist also auch das ausgereifteste Projekt.
Excalibur
Avalon Excalibur ist eine Reihe serverseitiger Komponenten, die Sie in Ihren eigenen Projekten verwenden können. Es umfasst die Implementierung von Pooling, Datenbankverbindungsmanagement und anderen Implementierungen des Komponentenmanagements.
LogKit
Avalon LogKit ist ein Hochgeschwindigkeits-Logging-Toolset, das von Framework, Excalibur, Cornerstone und Phoenix verwendet wird. Sein Modell verwendet die gleichen Prinzipien wie das JDK 1.4 Logging-Paket, ist jedoch mit JDK 1.2+ kompatibel.
Phoenix
Avalon Phoenix ist der Kern des Servers, der die Freigabe und Ausführung von Diensten verwaltet (Dienste, implementiert als serverseitige Komponenten, sogenannte Blöcke).
Cornerstone
Avalon Cornerstone ist eine Reihe von Blöcken oder Diensten, die in einer Phoenix-Umgebung bereitgestellt werden können. Diese Blöcke umfassen die Socket-Verwaltung und die Aufgabenplanung zwischen Blöcken.
Scratchpad
Scratchpad ist nicht wirklich ein formelles Projekt, sondern ein Bereitstellungsbereich für Komponenten, die noch nicht bereit sind, in Excalibur eingefügt zu werden. Die Qualität dieser Komponenten ist sehr unterschiedlich und es kann nicht garantiert werden, dass ihre APIs unverändert bleiben, bis sie zum Excalibur-Projekt befördert werden.

Höhepunkte dieser Übersicht
In dieser Übersicht konzentrieren wir uns auf das Avalon Framework, werden aber genügend Wissen über Avalon Excalibur und Avalon LogKit vermitteln, um Ihnen den Einstieg zu erleichtern. Wir werden anhand eines hypothetischen Business-Servers zeigen, wie man Avalon in der Praxis nutzt. Es würde den Rahmen dieser Übersicht sprengen, eine vollständige und umfassende Methodik zu definieren oder alle Aspekte aller Teilprojekte darzustellen. Wir konzentrieren uns auf das Avalon Framework, da es die Grundlage für alle anderen Projekte ist. Wenn Sie das Framework verstehen, können Sie jedes Avalon-basierte Projekt verstehen. Sie werden auch mit einigen gängigen Programmiersprachen (Redewendungen) vertraut gemacht, die häufig in Avalon verwendet werden. Ein weiterer Grund, sich auf Frameworks zu konzentrieren und die Projekte Avalon Excalibur und Avalon LogKit einzubeziehen, besteht darin, dass diese offiziell veröffentlicht und unterstützt werden.

Wo kann Avalon eingesetzt werden?
Ich wurde mehrfach gebeten, zu klären, wofür Avalon geeignet ist und wofür nicht. Avalon konzentriert sich auf serverseitige Programmierung und erleichtert das Entwerfen und Verwalten serveranwendungsorientierter Projekte. Avalon kann als Framework beschrieben werden, das eine Implementierung beinhaltet. Obwohl der Schwerpunkt von Avalon auf serverseitigen Lösungen liegt, finden viele Leute, dass es auch für allgemeine Anwendungen nützlich ist. Die in Framework, Excalibur und LogKit verwendeten Konzepte sind allgemein genug, um in jedem Projekt angewendet zu werden. Zwei Projekte, die sich direkter auf Server konzentrieren, sind Cornerstone und Phoenix. Rahmen
1. Eine unterstützende oder geschlossene Struktur 2. Ein grundlegendes System oder Arrangement, das Ideen enthält
Das Wort Framework hat in Anwendungen eine weit gefasste Bedeutung. Frameworks, die sich auf eine einzelne Branche konzentrieren, wie z. B. pharmazeutische Systeme oder Kommunikationssysteme, werden als vertikale Markt-Frameworks bezeichnet. Der Grund dafür ist, dass das gleiche Framework für andere Branchen nicht geeignet ist. Ein Framework, das sehr vielseitig ist und in mehreren Branchen eingesetzt werden kann, wird als horizontales Marktframework bezeichnet. Avalon ist ein horizontaler Marktrahmen. Sie können das Avalon-Framework verwenden, um ein vertikales Markt-Framework aufzubauen. Das überzeugendste Beispiel für ein mit Avalon erstelltes vertikales Markt-Framework ist das Apache Cocoon-Publishing-Framework. Apache Cocoon Version 2 wird mit Avalons Framework-, Excalibur- und LogKit-Projekten erstellt. Es nutzt die Schnittstellen und Verträge im Framework, sodass Entwickler weniger Zeit damit verbringen müssen, die Funktionsweise von Cocoon zu verstehen. Außerdem nutzt es effizient den von Excalibur bereitgestellten Datenquellenverwaltungs- und Komponentenverwaltungscode, sodass das Rad nicht neu erfunden werden muss. Schließlich wird LogKit verwendet, um alle Protokollierungsprobleme im Veröffentlichungsframework zu behandeln. Sobald Sie die Prinzipien hinter dem Avalon Framework verstanden haben, können Sie jedes auf Avalon basierende System verstehen. Sobald Sie das System verstanden haben, können Sie Fehler, die durch Missbrauch des Frameworks verursacht werden, schneller erkennen. Es gibt keine Zauberformel
Es ist erwähnenswert, dass jeder Versuch, ein Werkzeug als Zauberformel für den Erfolg zu verwenden, Ärger erfordert. Avalon ist keine Ausnahme. Da das Framework von Avalon für serverseitige Lösungen konzipiert ist, ist es keine gute Idee, es zum Erstellen grafischer Benutzeroberflächen (GUIs) zu verwenden. Java verfügt bereits über ein Framework zum Erstellen von GUIs namens Swing. Obwohl Sie überlegen müssen, ob Avalon für Ihr Projekt geeignet ist, können Sie dennoch etwas aus seinen Prinzipien und seinem Design lernen. Die Frage, die Sie sich stellen müssen, lautet: „Wo wird das Projekt verwendet?“ Wenn die Antwort lautet, dass es in einer Serverumgebung ausgeführt wird, ist Avalon eine gute Wahl, unabhängig davon, ob Sie ein Java-Servlet oder einen speziellen Zweck erstellen Serveranwendung. Wenn die Antwort lautet, dass es auf dem Computer eines Kunden läuft und keine Interaktion mit dem Server hat, dann ist Avalon möglicherweise nicht die richtige Wahl. Dennoch ist das Komponentenmodell sehr flexibel und hilft bei der Bewältigung der Komplexität großer Anwendungen.

Prinzipien und Muster
Avalon basiert auf einigen spezifischen Designprinzipien. Die beiden wichtigsten Modi sind „Inversion of Control“ und „Separation of Concerns“. Komponentenorientierte Programmierung, aspektorientierte Programmierung und serviceorientierte Programmierung haben auch Auswirkungen auf Avalon. Jedes Programmierprinzip könnte Bände von Büchern füllen, aber es handelt sich bei allen um Design-Thinking-Gewohnheiten. Inversion of Control
Das Konzept der Inversion of Control (IOC) bedeutet, dass Komponenten immer extern verwaltet werden. Dieser Satz wurde erstmals von Brian Foote in einer seiner Arbeiten verwendet. Alles, was die Komponente benötigt, wird der Komponente über Kontexte, Konfigurationen und Logger bereitgestellt. Tatsächlich wird jede Phase im Lebenszyklus einer Komponente durch den Code gesteuert, der die Komponente erstellt. Wenn Sie dieses Muster verwenden, implementieren Sie eine Methode für die sichere Interaktion von Komponenten mit Ihrem System. IOC ist nicht gleichbedeutend mit Sicherheit! IOC bietet einen Mechanismus, der es Ihnen ermöglicht, ein erweiterbares Sicherheitsmodell zu implementieren. Damit ein System wirklich sicher ist, muss jede Komponente sicher sein, keine Komponente kann den Inhalt der an sie übergebenen Objekte ändern und alle Interaktionen müssen bekannte Entitäten verwenden. Sicherheit ist ein wichtiges Anliegen, und IOC ist ein Werkzeug im Arsenal eines Programmierers, um Sicherheitsziele zu erreichen.

Separation of Concerns
Die Idee, dass Sie Ihr System aus verschiedenen Richtungen betrachten sollten, führte zum Muster der Separation of Concerns (SOC). Ein Beispiel ist die Betrachtung eines Webservers aus verschiedenen Perspektiven auf denselben Problembereich. Der Webserver muss sicher, stabil, verwaltbar und konfigurierbar sein und HTTP-Spezifikationen erfüllen. Jedes Attribut ist eine separate Überlegung. Einige dieser Überlegungen hängen mit anderen zusammen, beispielsweise mit Sicherheit und Stabilität (wenn ein Server instabil ist, kann er nicht sicher sein). Das separate Betrachtungsmodell führte zur Aspektorientierten Programmierung (AOP). Forscher haben herausgefunden, dass viele Überlegungen nicht auf der Klassen- oder Methodengranularität berücksichtigt werden können. Diese Überlegungen werden Aspekte genannt. Beispiele für Aspekte sind die Verwaltung von Objektlebenszyklen, die Protokollierung, die Behandlung von Ausnahmen sowie das Bereinigen und Freigeben von Ressourcen. Da es keine stabile AOP-Implementierung gibt, hat sich das Avalon-Entwicklungsteam dafür entschieden, Aspekte oder Überlegungen durch die Bereitstellung einiger kleiner Schnittstellen umzusetzen, die dann durch Komponenten implementiert werden.
Komponentenorientierte Programmierung
Komponentenorientierte Programmierung (Component Oriented Programming, COP) ist eine Idee, das System in einige Komponenten oder Einrichtungen zu unterteilen. Jede Einrichtung verfügt über eine Arbeitsschnittstelle und einen Vertrag, der diese Schnittstelle umgibt. Dieser Ansatz ermöglicht den einfachen Austausch von Komponenteninstanzen, ohne dass sich dies auf den Code in anderen Teilen des Systems auswirkt. Der Hauptunterschied zwischen objektorientierter Programmierung (OOP) und COP ist der Grad der Integration. Die Komplexität von COP-Systemen ist dank weniger gegenseitiger Abhängigkeiten zwischen Klassen einfacher zu bewältigen. Dies erhöht den Grad der Code-Wiederverwendung. Einer der Hauptvorteile von COP besteht darin, dass die Änderung einiger Teile des Projektcodes nicht das gesamte System beschädigt. Ein weiterer Vorteil besteht darin, dass Sie mehrere Implementierungen einer Komponente haben und diese zur Laufzeit auswählen können.
Serviceorientierte Programmierung
Die Idee der serviceorientierten Programmierung (SOP) besteht darin, das System in einige vom System bereitgestellte Dienste aufzuteilen. Dienstleistung
1. Für andere ausgeführte Arbeiten oder Pflichten 2. Eine Einrichtung, die Reparaturen oder Wartungsarbeiten durchführt 3. Eine Einrichtung, die Werkzeuge für die Öffentlichkeit bereitstellt
Avalon’s Phoenix betrachtet jede bereitzustellende Einrichtung als eine Dienstleistung, die aus einer bestimmten Dienstleistung besteht Schnittstelle und zugehörige Verträge. Die Implementierung eines Dienstes wird als Block bezeichnet. Es ist wichtig zu verstehen, dass ein Serverprogramm aus mehreren Diensten besteht. Am Beispiel eines Mailservers verfügt dieser über Protokollverarbeitungsdienste, Authentifizierungs- und Autorisierungsdienste, Verwaltungsdienste und zentrale Mailverarbeitungsdienste. Cornerstone von Avalon bietet einige Low-Level-Dienste, die Sie in Ihrem eigenen System nutzen können. Zu den bereitgestellten Diensten gehören Verbindungsverwaltung, Socket-Verwaltung, Teilnehmer-/Rollenverwaltung und -planung usw. Wir stellen hier Dienste vor, da sie sich auf den Prozess der Zerlegung unseres hypothetischen Systems in verschiedene Einrichtungen beziehen.

Aufschlüsselung eines Systems

Wie entscheiden Sie, was eine Komponente ausmacht? Der Schlüssel liegt darin, die Einrichtungen zu definieren, die Ihre Lösung benötigt, um effizient zu funktionieren.
Wir werden anhand eines hypothetischen Business-Servers zeigen, wie Dienste und Komponenten identifiziert und bestimmt werden. Nachdem wir einige vom System verwendete Dienste definiert haben, nehmen wir einen dieser Dienste als Beispiel und definieren die verschiedenen Komponenten, die für diesen Dienst erforderlich sind. Mein Ziel ist es, Ihnen einige Konzepte zu vermitteln, die Ihnen helfen, Ihr System in überschaubare Teile zu zerlegen.

Systemanalyse – Komponenten identifizieren
Obwohl es den Rahmen dieses Artikels sprengt, eine vollständige und umfassende Methodik bereitzustellen, möchte ich einige Themen besprechen. Wir beginnen mit umsetzungsorientierten Definitionen von Komponenten und Diensten und geben dann eine praktische Definition. Komponente
Eine Komponente ist eine Kombination aus einer Worker-Schnittstelle und einer Implementierung dieser Worker-Schnittstelle. Die Verwendung von Komponenten sorgt für eine lose Kopplung zwischen Objekten, sodass die Implementierung geändert werden kann, ohne dass sich dies auf den Code auswirkt, der sie verwendet.
Service
Ein Service besteht aus einer oder mehreren Komponenten und bietet eine Komplettlösung. Beispiele für Dienste sind Protokollhandler, Aufgabenplaner, Authentifizierungs- und Autorisierungsdienste usw.
Obwohl diese Definitionen einen Ausgangspunkt darstellen, liefern sie kein vollständiges Bild. Um ein System (definiert als eine Reihe von Einrichtungen, aus denen ein Projekt besteht) in seine notwendigen Komponenten zu zerlegen, empfehle ich einen Top-Down-Ansatz. Dieser Ansatz vermeidet, dass Sie sich in Details verzetteln, bevor Sie genau wissen, welche Einrichtungen verfügbar sind. Bestimmen Sie den Umfang Ihres Projekts
Welche Funktionen Ihr Projekt erfüllen soll, sollten Sie zu Beginn immer eine grobe Vorstellung haben. In der Geschäftswelt genügt eine erste Leistungsbeschreibung. In der Open-Source-Welt geschieht dies meist mit einer Idee oder einem Brainstorming-Prozess. Ich denke, wie wichtig es ist, einen umfassenden Überblick über ein Projekt zu haben, kann nicht genug betont werden. Es ist offensichtlich, dass ein großes Projekt aus vielen verschiedenen Diensten bestehen wird, während ein kleines Projekt nur einen oder zwei Dienste hat. Wenn Sie sich ein wenig überfordert fühlen, erinnern Sie sich einfach daran, dass große Projekte eigentlich viele kleinere Projekte unter einem großen Dach sind. Schließlich werden Sie in der Lage sein, das Gesamtbild des gesamten Systems zu verstehen.

Arbeitsbeschreibung: Business Server
Business Server (Business Server) ist ein hypothetisches Projekt. Für die Zwecke unserer Diskussion besteht seine Funktionalität darin, Kundenaufträge zu verarbeiten, automatisch Rechnungen an Kunden auszustellen und die Bestandskontrolle zu verwalten. Kundenaufträge müssen bei Eingang über eine Art Transaktionssystem verarbeitet werden. Der Server stellt dem Kunden 30 Tage nach Ausführung des Kundenauftrags automatisch eine Rechnung aus. Der Bestand wird sowohl vom Server als auch vom aktuellen Bestand in der Fabrik oder im Lager verwaltet. Der Unternehmensserver wird ein verteiltes System sein und jeder Server kommuniziert mit anderen Servern über einen Nachrichtendienst.
Dienste entdecken
Wir werden dieses Business Server-Projekt verwenden, um Dienste zu entdecken. Betrachtet man die allzu allgemeine Leistungsbeschreibung oben, erkennt man sofort einige der in der Projektbeschreibung definierten Leistungen. Die Liste der Dienste kann in zwei große Kategorien unterteilt werden: explizite Dienste (Dienste, die direkt aus der Werkbeschreibung abgeleitet werden können) und implizite Dienste (Dienste, die auf der Grundlage ähnlicher Arbeiten entdeckt werden, oder Dienste, die explizite Dienste unterstützen). Beachten Sie, dass das Unternehmen, das das System implementiert, nicht alle Dienste selbst entwickeln muss – einige können als kommerzielle Lösungen erworben werden. In diesen Fällen entwickeln wir möglicherweise einen Wrapper, der es uns ermöglicht, auf deterministische Weise mit kommerziellen Produkten zu interagieren. Das Unternehmen, das das System implementiert, wird die meisten Dienste erstellen. Explizite Dienste
Aus der Leistungsbeschreibung können wir einige Dienste schnell exportieren. Diese erste Analyse bedeutet jedoch nicht, dass unsere Arbeit abgeschlossen ist, da die Definition einiger Dienste die Existenz anderer Dienste voraussetzt, um sicherzustellen, dass sie vorhanden sind. Transaktionsverarbeitungsdienste
In der Stellenbeschreibung heißt es eindeutig: „Kundenaufträge müssen bearbeitet werden, sobald sie eingehen.“ Dies legt nahe, dass wir einen Mechanismus benötigen, um Verkaufsanfragen anzunehmen und automatisch zu verarbeiten. Dies ähnelt der Funktionsweise von Webservern. Sie erhalten eine Anfrage für eine Ressource, verarbeiten diese und geben ein Ergebnis (z. B. eine HTML-Seite) zurück. Dies wird als Transaktionsverarbeitung bezeichnet. Der Vollständigkeit halber: Es gibt verschiedene Arten von Transaktionen. Dieser allgemeine Transaktionsverarbeitungsdienst muss höchstwahrscheinlich in etwas Spezifischeres unterteilt werden, beispielsweise in einen „Auftragsabwickler“. Die genaue Methode hängt von der Allgemeinheit Ihres Dienstes ab. Es besteht ein Gleichgewicht zwischen Benutzerfreundlichkeit und Wiederverwendbarkeit. Je allgemeiner ein Dienst ist, desto häufiger ist er wiederverwendbar. Es ist meist auch schwieriger zu verstehen.
Planungsservice
In einigen Fällen muss nach Abschluss einer Transaktion nach einem bestimmten Zeitraum ein Ereignis geplant werden. Darüber hinaus muss der Bestandskontrollprozess in der Lage sein, regelmäßig Bestellungen auszugeben. Da in der Stellenbeschreibung steht, dass „30 Tage nach Ausführung des Kundenauftrags der Server automatisch eine Rechnung an den Kunden ausstellt“, benötigen wir einen Terminplanungsservice. Glücklicherweise stellt uns Avalon Cornerstone eines zur Verfügung, sodass wir nicht selbst eines schreiben müssen.
Nachrichtendienst
In der Arbeitsbeschreibung heißt es, dass in unserem verteilten System „jeder Server über einen Nachrichtendienst mit anderen Servern kommuniziert“. Denken wir einmal darüber nach: Manchmal möchten Benutzer ein bestimmtes Produkt oder eine Methode, die sie verwenden möchten. Messaging-Dienste sind ein Paradebeispiel für die Nutzung der Produkte anderer Unternehmen. Höchstwahrscheinlich werden wir Java Messaging Service (JMS) als Schnittstelle des Messaging Service verwenden. Da es sich bei JMS um einen Standard handelt, ist es unwahrscheinlich, dass sich seine Schnittstelle in absehbarer Zeit ändern wird. Aus praktischer Erfahrung ist ein wohldefiniertes nachrichtenorientiertes System skalierbarer als ein objektorientiertes System (wie EJB). Ein Grund für die bessere Skalierbarkeit besteht darin, dass Nachrichten im Allgemeinen gleichzeitig weniger Speicheraufwand verursachen. Ein weiterer Grund besteht darin, dass es einfacher ist, die Last der Nachrichtenverarbeitung auf alle Server zu verteilen, als die gesamte Verarbeitung auf einen kleinen Servercluster (oder sogar auf einen einzelnen Server) zu konzentrieren.
Bestandskontrolldienst
Obwohl dies kein klassischer Dienst nach Lehrbuch ist, ist er eine Voraussetzung für dieses System. Der Bestandskontrolldienst überwacht ständig die Aufzeichnungen des Fabrik- oder Lagerbestands und löst Ereignisse aus, wenn der Bestand zur Neige geht.

Implizite Dienste
Wenn wir die in früheren Systemen gesammelten Erfahrungen nutzen, um das System weiter in andere Dienste zu zerlegen, erhalten wir einige Dienste, auf die nicht explizit hingewiesen wird, die aber vom System benötigt werden. Aus Platzgründen können wir auf eine umfassende Aufschlüsselung verzichten. Authentifizierungs- und Autorisierungsdienste
Authentifizierungs- und Autorisierungsdienste werden in der Stellenbeschreibung nicht explizit erwähnt, aber alle Geschäftssysteme müssen die Sicherheit ernsthaft berücksichtigen. Das bedeutet, dass alle Clients des Systems authentifiziert und alle Benutzeraktionen autorisiert sein müssen.
Workflow-Automatisierungsdienste
Workflow-Automatisierung ist ein beliebter Entwicklungsbereich in Unternehmenssystemen. Wenn Sie keinen Workflow-Management-Server eines Drittanbieters verwenden, müssen Sie selbst einen schreiben. Bei der Workflow-Automatisierung werden in der Regel Softwaresysteme eingesetzt, um Aufgaben in den Geschäftsprozessen eines Unternehmens zu planen. Weitere Informationen finden Sie auf der Website des Workflow Management Council unter http://www.wfmc.org/.
Document Center Service
Als aktuelle Statusinformation einer Aufgabe ist die Definition des Begriffs „Document Center“ sehr ungenau. Mit anderen Worten: Wenn ein Unternehmen eine Bestellung erhält, muss unser System in der Lage sein, die Bestellinformationen zu speichern und abzurufen. Für die Abrechnung gelten dieselben Anforderungen wie für jeden anderen Prozess im System, vom Inventar bis hin zu neuen Benutzeranfragen.

Zusammenfassung
Ich hoffe, die Beispiele für Dienste im Business Server-Projekt können Ihnen dabei helfen, mehr zu entdecken. Sie werden feststellen, dass beim Übergang von höheren zu niedrigeren Abstraktionsschichten mehr Arten von Diensten erforderlich sind, beispielsweise ein Verbindungsdienst zur Bearbeitung von Anforderungen an einen offenen Port. Einige der von uns definierten Dienste werden über Systeme von Drittanbietern implementiert, beispielsweise Messaging-Dienste und Workflow-Management-Dienste. Für diese Dienste ist es in Ihrem Interesse, eine Standardschnittstelle zu nutzen, damit Sie später den Anbieter wechseln können. Bei einigen Diensten handelt es sich tatsächlich um große Dienste, die aus mehreren Diensten bestehen. Einige Dienste werden bereits in Avalon Excalibur oder Avalon Cornerstone bereitgestellt. Wenn Sie Dienste in einem System ermitteln, sollten Sie bedenken, dass es sich bei einem Dienst um ein Subsystem auf hoher Ebene handeln sollte. Dies wird Ihnen helfen, Komponenten durch ein Team von Analysten zu definieren. Da wir die wichtigsten Dienste identifiziert haben, können Sie jeden Dienst von mehreren Personen (oder Teams) parallel aufschlüsseln lassen. Auch die Grenzen der Subsysteme sind gut definiert und die Wahrscheinlichkeit einer Überlappung ist gering. Wenn Sie sich für eine parallele Analyse entscheiden, sollten Sie zurückgehen und gemeinsame Komponenten identifizieren, damit sie so weit wie möglich wiederverwendet werden können.

UML-Diagramm für den Business Server

Erkennen von Komponenten
Wir verwenden den zuvor erwähnten Document Center-Dienst als Beispiel, um den Prozess der Identifizierung geeigneter Komponenten zu veranschaulichen. Der Diskussion halber listen wir nun die Anforderungen für Document Center-Dienste auf. Das Document Center nutzt eine Datenbank als dauerhaften Speicher, autorisiert Clients und speichert Dokumente im Speicher. Praktische Definition von Komponenten
Wenn wir über Komponenten sprechen, sollten Sie darüber nachdenken: Welche Einrichtungen benötigt mein Dienst für den Betrieb? Avalon glaubt an das Konzept, ein System zu erschaffen. Entwickler eines Systems stehen vor einer Liste von Verantwortlichkeiten für eine Komponente, der sogenannten Rolle. Was ist eine Rolle?
Der Rollenbegriff stammt aus dem Theater. In einem Theaterstück, Musical oder Film gibt es eine bestimmte Anzahl von Charakteren, die von Schauspielern gespielt werden. Obwohl es nie an Schauspielern zu mangeln scheint, ist die Anzahl der Rollen begrenzt. Das Drehbuch einer Show definiert die Funktion oder das Verhalten einer Figur. Genau wie im Theater bestimmt das Drehbuch, wie Sie mit den Komponenten interagieren. Denken Sie über die verschiedenen Akteure im System nach. Sie projizieren die Komponenten auf die Akteure und sprechen mit ihnen. Eine Rolle ist ein Vertrag für eine Klasse von Komponenten. Beispielsweise muss unser Document Center-Service eine Datenbank betreiben. Avalon Excalibur definiert eine Komponente, die die Anforderungen der Rolle „Datenquelle“ erfüllt. In Excalibur gibt es zwei verschiedene Komponenten, die beide die Anforderungen dieser Rolle erfüllen. Welche verwendet werden soll, hängt von der Umgebung ab, in der sich der Dienst befindet. Sie erfüllen jedoch alle denselben Vertrag. Viele Avalon-basierte Systeme verwenden nur eine aktive Komponente pro Charakter. Skripte sind Arbeitsschnittstellen: Schnittstellen, mit denen andere Komponenten interagieren. Wenn Sie die Schnittstelle einer Komponente festlegen, müssen Sie einen eindeutigen Vertrag haben und diesen im Auge behalten. Der Vertrag legt fest, was Nutzer der Komponente bereitstellen müssen und was die Komponente produziert. Manchmal muss die Nutzungssemantik in einen Vertrag aufgenommen werden. Ein Beispiel ist der Unterschied zwischen temporären Speicherkomponenten und persistenten Speicherkomponenten. Sobald die Schnittstellen und Protokolle definiert sind, können Sie an deren Implementierung arbeiten.

Was macht eine gute Kandidatenkomponente aus?
In unserem Document Center-Service haben wir vier mögliche Komponenten identifiziert: DataSourceComponent (von Excalibur), Cache, Repository, Guardian. Sie sollten nach Rollen suchen, die wahrscheinlich über mehrere Implementierungen verfügen, mit denen eine nahtlose Interaktion erfolgen kann. Anhand dieses Beispiels werden Sie erkennen, dass es Situationen gibt, in denen Sie alternative Einrichtungen nutzen müssen. In den meisten Fällen werden Sie nur eine Implementierung dieser Funktion verwenden, Sie müssen diese jedoch unabhängig aktualisieren können, ohne den Rest des Systems zu beeinträchtigen. In anderen Fällen müssen Sie je nach Umgebung unterschiedliche Implementierungen verwenden. Beispielsweise übernimmt die von Excaliber definierte „Datenquelle“ normalerweise das gesamte JDBC-Verbindungspooling selbst, aber manchmal möchten Sie vielleicht die Vorteile der Java 2 Enterprise Edition (J2EE) nutzen. Excalibur löst dieses Problem, indem eine „Datenquellen“-Komponente JDBC-Verbindungen und -Pools direkt verwaltet und eine andere Komponente das Naming and Directory Interface (JNDI) von Java verwendet, um bestimmte Verbindungen zu erhalten.
Was ist keine gute Komponente?
Menschen, die es gewohnt sind, JavaBeans zu verwenden, implementieren gerne alles als JavaBean. Dies umfasst alles von Datenmodellen bis hin zur Transaktionsverarbeitung. Wenn Sie Komponenten auf diese Weise angehen, erhalten Sie möglicherweise ein übermäßig komplexes System. Stellen Sie sich eine Komponente als Modell eines Dienstes oder einer Einrichtung vor und nicht als Datenmodell. Sie können über Komponenten verfügen, die Daten aus anderen Quellen abrufen, die Daten sollten jedoch weiterhin Daten bleiben. Ein Beispiel für diese Philosophie in Avalon Excalibur ist, dass die Verbindung keine Komponente ist. Ein weiteres Beispiel ist die zuvor erwähnte Guardian-Komponente. Man könnte argumentieren, dass die in Guardian enthaltene Logik zu relevant für den Document Center-Dienst ist und nicht als Komponente in einem völlig anderen Dienst verwendet werden kann. Obwohl es viele Möglichkeiten gibt, mit Komplexität umzugehen und sie flexibel zu gestalten, lohnt sich die zusätzliche Arbeit manchmal nicht. In diesem Fall müssen Sie Ihre Entscheidung sorgfältig abwägen. Wenn die Logik einer potenziellen Komponente konsistent angewendet wird, kann es sinnvoll sein, sie als Komponente zu behandeln. In einem System kann es mehrere Instanzen einer Komponente geben, die zur Laufzeit ausgewählt werden können. Wenn die Logik der zugrunde liegenden Komponente nur von einer anderen Komponente bestimmt wird, kann es möglich sein, die Logik in diese andere Komponente einzufügen. Anhand der Beispiele der Guardian-Komponente und der Repository-Komponente können wir argumentieren, dass Guardian sich zu sehr auf das Repository konzentriert und nicht als Komponente implementiert ist.
Aufschlüsselung des Dokumentationszentrumsdienstes
Wir werden die Komponenten auflisten, die implementiert werden, zusammen mit ihren Rollen, Grundursachen und Quellen (sofern die Komponenten bereits vorhanden sind). DocumentRepository
DocumentRepository ist die übergeordnete Komponente des gesamten Dienstes. In Avalon werden Dienste als Blöcke implementiert, bei denen es sich um Komponenten eines bestimmten Typs handelt. Der Block muss über eine funktionierende Schnittstelle verfügen, die die Service-Marker-Schnittstelle erweitert. Die Block-Schnittstelle erweitert auch die Component-Schnittstelle von Avalon. Bitte beachten Sie, dass Block und Service in Avalon Phoenix enthaltene Schnittstellen sind. Schließlich ist Service technisch gesehen immer noch ein spezifischer Komponententyp. Mit DocumentRepository erhalten wir Dokumentobjekte aus dem persistenten Speicher. Es interagiert mit anderen Komponenten des Dienstes, um Sicherheit, Funktionalität und Geschwindigkeit bereitzustellen. Dieses spezifische DocumentRepository stellt eine Verbindung zur Datenbank her und verwendet die Datenbanklogik intern, um Dokumentobjekte zu erstellen.
DataSourceComponent
DataSourceComponent wird von Avalon Excalibur bereitgestellt. Auf diese Weise erhalten wir ein gültiges JDBC-Verbindungsobjekt.
Cache
Cache ist eine kurzfristige In-Memory-Speichereinrichtung. DocumentRepository verwendet es, um Dokumentobjekte zu speichern und über einen Hashing-Algorithmus auf sie zu verweisen. Um die Wiederverwendbarkeit von Cache-Komponenten zu verbessern, müssen gespeicherte Objekte eine Cacheable-Schnittstelle implementieren.
Guardian
Die Rolle der Guardian-Komponente basiert auf den Verwaltungsberechtigungen der Teilnehmer. Guardian lädt den Lizenzregelsatz aus der Datenbank. Guardian verwendet das Standard-Java-Sicherheitsmodell, um den Zugriff auf ein bestimmtes Dokument zu gewährleisten.

Zusammenfassung
Inzwischen sollten Sie eine Vorstellung davon haben, was eine gute Komponente ausmacht. Das Beispiel beschreibt alle Komponenten im Document Center-Dienst und stellt kurz die Arbeit vor, die sie leisten werden. Ein kurzer Blick auf diese Liste verdeutlicht den Ansatz, Einrichtungen als Komponenten und nicht als Daten zu implementieren. Jetzt sollten Sie in der Lage sein, zu bestimmen, welche Komponenten Ihr Dienst zum Betrieb benötigt.

Rahmen und Grundlage

Wir werden die Verträge und Schnittstellen von Avalon beschreiben, um die Grundlage dafür zu legen, dass wir tatsächlich Komponenten schreiben können.
Avalon Framework ist der zentrale Teil des gesamten Avalon-Projekts. Wenn Sie die von einem Framework definierten Verträge und Strukturen verstehen, können Sie jeden Code verstehen, der dieses Framework nutzt. Erinnern Sie sich an die Prinzipien und Muster, die wir besprochen haben. In diesem Abschnitt erklären wir ausführlich, wie das Konzept der Rollen in der Praxis funktioniert, den Lebenszyklus von Komponenten und die Funktionsweise von Schnittstellen.

Die Rolle einer Komponente definieren
In Avalon spielen alle Komponenten eine Rolle. Der Grund dafür ist, dass Sie Ihre Komponenten über Rollen erhalten. In diesem Bereich müssen wir nur die Unterschrift des Charakters berücksichtigen. Erinnern Sie sich an Teil 2, dass wir eine Komponente als „eine Kombination aus einer Arbeitsschnittstelle und einer Implementierung dieser Arbeitsschnittstelle“ definiert haben. Die Arbeitsschnittstelle ist die Rolle. Erstellen einer Schnittstelle für eine Rolle
Unten sehen Sie ein Beispiel einer Schnittstelle sowie einige Best Practices und Gründe dafür. package org.apache.bizserver.docs;public interface DocumentRepository erweitert Component{ String ROLE = DocumentRepository.class.getName(); Document getDocument(Principal requestor, int refId);}
Best Practice
· Enthält einen Namen A Zeichenfolge für „ROLE“, der offizielle Name der Rolle. Dieser Name ist derselbe wie der vollständig qualifizierte Name der Worker-Schnittstelle. Dies wird in Zukunft hilfreich sein, wenn wir eine Instanz einer Komponente benötigen. · Wenn möglich, erweitern Sie bitte die Komponentenschnittstelle. Dies erleichtert die Veröffentlichung Ihrer Komponenten. Wenn Sie nicht für die Steuerung der Arbeitsoberfläche verantwortlich sind, nützt Ihnen das nichts. Dies stellt kein allzu großes Problem dar, da Sie es beim Veröffentlichen jederzeit in eine Instanz von Component umwandeln können. · Machen Sie eine Sache und machen Sie sie gut. Die Schnittstelle einer Komponente sollte möglichst einfach sein. Wenn Ihre Arbeitsschnittstelle eine andere Schnittstelle erweitert, wird es schwierig, den Vertrag der Komponente zu verstehen. Ein altes amerikanisches Akronym bringt dies gut auf den Punkt: Keep It Simple, Stupid (KISS). Es ist nicht schwer, schlauer (und dümmer) zu sein als man selbst, ich habe es selbst schon ein paar Mal getan. · Identifizieren Sie nur die Methoden, die Sie benötigen. Das Client-Programm sollte keine Implementierungsdetails kennen, und zu viele alternative Methoden führen nur zu unnötiger Komplexität. Mit anderen Worten: Wählen Sie einen Weg und bleiben Sie dabei. · Lassen Sie nicht zu, dass Ihre Charakterschnittstelle den Lebenszyklus oder die Überlebensschnittstelle verlängert. Wenn Sie eine solche Klasse oder Schnittstelle implementieren, versuchen Sie, die Spezifikation zu implementieren. Dies ist kein gutes Muster und wird in Zukunft nur zu Debugging- und Implementierungsproblemen führen.
Wählen Sie einen Charakternamen
In Avalon hat jeder Charakter einen Namen. Auf diese Weise erhalten Sie Verweise auf andere Komponenten im System. Das Avalon-Entwicklerteam hat einige Konventionen für die Benennung von Charakteren dargelegt. Namenskonvention
· Der vollqualifizierte Name der Arbeitsschnittstelle ist in der Regel der Rollenname. Ausnahmen sind im Folgenden dieser allgemeinen Regeln aufgeführt. In diesem Beispiel sollte unser theoretischer Komponentenname „org.apache.bizserver.docs.DocumentRepository“ lauten. Dies ist der Name, der im „ROLE“-Attribut Ihrer Schnittstelle enthalten sein sollte. · Wenn wir über einen Komponentenselektor einen Verweis auf die Komponente erhalten, verwenden wir normalerweise den aus der ersten Regel abgeleiteten Rollennamen und am Ende das Wort „Selektor“. Das Ergebnis dieser Benennungsregel ist „org.apache.bizserver.docs.DocumentRepositorySelector“. Diesen Namen erhalten Sie über DocumentRepository.ROLE + „Selector“. · Wenn wir über mehrere Komponenten verfügen, die dieselbe Arbeitsschnittstelle implementieren, aber unterschiedlichen Zwecken dienen, werden wir die Rollen trennen. Eine Rolle ist der Zweck einer Komponente in einem System. Jeder Charaktername beginnt mit dem ursprünglichen Charakternamen, aber der Zweckname des Charakters wird in der Form /${Zweck} angehängt. Für DocumentRePository können wir beispielsweise die folgenden Zwecke haben: PurchaseOrder (Bestellung) und Bill (Rechnung). Diese beiden Rollen können als DocumentRepository.ROLE + „/PurchaseOrder“ bzw. DocumentRepository.ROLE + „/Bill“ ausgedrückt werden.

Übersicht über die Framework-Schnittstelle
Das gesamte Avalon Framework kann in sieben Hauptkategorien (je nach API) unterteilt werden: Aktivität, Komponente, Konfiguration, Kontext, Logger, Parameter, Thread und Verschiedenes. Jede Kategorie (außer „Verschiedenes“) stellt einen Problembereich dar. Eine Komponente implementiert normalerweise mehrere Schnittstellen, um die Betrachtungsrichtung anzugeben, die ihr wichtig ist. Dadurch kann der Komponentencontainer jede Komponente auf konsistente Weise verwalten. Lebenszyklus der Avalon-Schnittstelle
Wenn ein Framework mehrere Schnittstellen implementiert, um verschiedene Aspekte der Komponente separat zu betrachten, besteht die Gefahr von Verwirrung über die Reihenfolge der Methodenaufrufe. Das Avalon Framework erkennt dies, daher haben wir ein Protokoll für die Reihenfolge des Ereignislebenszyklus entwickelt. Wenn Ihre Komponente die entsprechende Schnittstelle nicht implementiert, springt sie einfach zum nächsten zu verarbeitenden Ereignis. Da es eine korrekte Methode zum Erstellen und Vorbereiten von Komponenten gibt, können Sie die Komponente einrichten, wenn das Ereignis empfangen wird. Der Lebenszyklus einer Komponente ist in drei Phasen unterteilt: Initialisierungsphase, Aktivitätsdienstphase und Zerstörungsphase. Da diese Phasen nacheinander ablaufen, werden wir sie der Reihe nach besprechen. Darüber hinaus werden Konstruktion und Finalisierung aufgrund der Java-Sprache implizit ausgeführt, sodass wir sie überspringen. Wir listen den Methodennamen und die erforderliche Schnittstelle auf. Innerhalb jeder Phase gibt es Schritte, die durch Methodennamen identifiziert werden. Wenn die Komponente die in Klammern angegebene Schnittstelle erweitert, werden diese Schritte nacheinander ausgeführt. Initialisierungsphase
Die folgenden Schritte erfolgen nacheinander und kommen nur einmal während der Lebensdauer der Komponente vor. 1. enableLogging() [LogEnabled] 2. contextualize() [Kontextualisierbar] 3. compose() [Zusammensetzbar] 4. configure() [Konfigurierbar] oder parametrisieren() [Parametrierbar] 5. initialize() [Initialisierbar] 6. start () [Startbar]
Aktive Servicephase
Die folgenden Schritte erfolgen nacheinander, können jedoch während der Lebensdauer der Komponente mehrmals auftreten. Beachten Sie, dass es in der Verantwortung Ihrer Komponente liegt, die korrekte Funktionalität sicherzustellen, wenn Sie die Suspendable-Schnittstelle nicht implementieren, wenn Sie alle Schritte ausführen, die mit re beginnen. 1. suspend() [Suspendable] 2. recontextualize() [Recontextualizable] 3. recompose() [Recomposable] 4. reconfigure() [Reconfigurable] 5. resume() [Suspendable]
Zerstörungsphase
nach dem Schritte erfolgen nacheinander und nur einmal während der Lebensdauer der Komponente. 1. stop() [Startable] 2. dispose() [Disposable]

Avalon-Rahmenvertrag
In diesem Abschnitt werden wir alles in alphabetischer Reihenfolge behandeln, mit Ausnahme des wichtigsten Teils: Komponente, Wir setzen es vorne. Wenn ich „Container“ oder „Container“ verwende, um Komponenten zu beschreiben, habe ich eine besondere Bedeutung. Ich meine die untergeordneten Komponenten, die von der übergeordneten Komponente instanziiert und gesteuert wurden. Ich meine nicht die Komponenten, die Sie über ComponentManager oder ComponentSelector erhalten. Darüber hinaus müssen einige von der Containerkomponente empfangene Avalon-Schrittausführungsbefehle an alle ihre Unterkomponenten weitergegeben werden, solange diese Unterkomponenten die entsprechende Schnittstelle implementieren. Spezifische Schnittstellen sind „initialisierbar“, „startbar“, „suspendierbar“ und „verfügbar“. Der Grund für diese Anordnung der Verträge liegt darin, dass für diese Schnittstellen besondere Ausführungskonventionen gelten. Komponente
Dies ist der Kern des Avalon Framework. Die durch diese Betrachtungsrichtung definierte Schnittstelle löst ComponentException aus. Komponente
Jede Avalon-Komponente muss die Komponentenschnittstelle implementieren. Component Manager und Component Selector befassen sich nur mit Komponenten. Diese Schnittstelle hat keine definierten Methoden. Es dient lediglich als Token-Schnittstelle. Jede Komponente muss den Standardkonstruktor ohne Parameter verwenden. Die gesamte Konfiguration erfolgt über die konfigurierbare oder parametrierbare Schnittstelle.
Zusammensetzbar
Eine Komponente, die andere Komponenten verwendet, muss diese Schnittstelle implementieren. Diese Schnittstelle verfügt nur über eine Methode compose(), die einen einzelnen Parameter vom Typ ComponentManager akzeptiert. Der diese Schnittstelle umgebende Vertrag sieht vor, dass compose() einmal und nur einmal während der Lebensdauer der Komponente aufgerufen wird. Diese Schnittstelle verwendet wie jede andere Schnittstelle, die Methoden definiert, das Reverse-Control-Muster. Es wird vom Container der Komponente aufgerufen und nur die von der Komponente benötigten Komponenten werden im ComponentManager angezeigt.
Wiederzusammensetzbar
In seltenen Fällen erfordert eine Komponente einen neuen ComponentManager und eine neue Komponenten-Rollenzuordnung. In diesen Fällen muss die neu zusammensetzbare Schnittstelle implementiert werden. Sein Methodenname unterscheidet sich auch von dem von Composable, nämlich recompose(). Der Vertrag rund um diese Schnittstelle besteht darin, dass die recompose()-Methode beliebig oft aufgerufen werden kann, jedoch nicht, bevor die Komponente vollständig initialisiert ist. Wenn diese Methode aufgerufen wird, muss sich die Komponente auf sichere und konsistente Weise selbst aktualisieren. Normalerweise bedeutet dies, dass alle von der Komponente ausgeführten Vorgänge zwischen den Aktualisierungen angehalten und nach den Aktualisierungen wieder aufgenommen werden müssen.

Aktivität
Dieser Satz von Schnittstellen steht im Zusammenhang mit dem Vertrag des Komponentenlebenszyklus. Wenn während dieser Reihe von Schnittstellenaufrufen ein Fehler auftritt, können Sie eine generische Ausnahme auslösen. Einweg
Wenn eine Komponente strukturiert wissen muss, dass sie nicht mehr benötigt wird, kann sie die Schnittstelle „Disposable“ nutzen. Sobald eine Komponente freigegeben wurde, kann sie nicht mehr verwendet werden. Tatsächlich wartet es nur darauf, im Müll gesammelt zu werden. Diese Schnittstelle verfügt nur über eine Methode dispose(), die keine Parameter hat. Der diese Schnittstelle umgebende Vertrag sieht vor, dass die dispose()-Methode einmal aufgerufen wird und die letzte Methode ist, die während der Lebensdauer der Komponente aufgerufen wird. Es zeigt auch an, dass die Komponente nicht mehr verwendet wird und die von der Komponente belegten Ressourcen freigegeben werden müssen.
Initialisierbar
Wenn eine Komponente andere Komponenten erstellen oder Initialisierungsvorgänge ausführen muss, um Informationen aus anderen Initialisierungsschritten zu erhalten, muss sie die Schnittstelle Initialisierbar verwenden. Diese Schnittstelle verfügt nur über eine initialize()-Methode, die keine Parameter hat. Der diese Schnittstelle umgebende Vertrag sieht vor, dass die Methode initialize() einmal aufgerufen wird und die letzte Methode ist, die während des Initialisierungsprozesses aufgerufen wird. Es zeigt außerdem an, dass die Komponente aktiv ist und von anderen Komponenten im System verwendet werden kann.
Startable
Wenn eine Komponente während ihrer Lebensdauer weiterhin ausgeführt wird, muss sie die Startable-Schnittstelle verwenden. Diese Schnittstelle definiert zwei Methoden: start() und stop(). Beide Methoden haben keine Parameter. Der diese Schnittstelle umgebende Vertrag sieht vor, dass die start()-Methode einmal aufgerufen wird, nachdem die Komponente vollständig initialisiert wurde. Die Methode stop() wird einmal aufgerufen, bevor die Komponente zerstört wird. Keiner von ihnen wird zweimal aufgerufen. start() wird immer vor stop() aufgerufen. Implementierungen dieser Schnittstelle sind erforderlich, um die Methoden start() und stop() sicher (im Gegensatz zur Methode Thread.stop()) und ohne Systeminstabilität auszuführen.
Suspendable
Wenn sich eine Komponente während ihrer Lebensdauer suspendieren lässt, muss sie die Suspendable-Schnittstelle verwenden. Obwohl es normalerweise immer mit der Startable-Schnittstelle verwendet wird, ist dies nicht erforderlich. Diese Schnittstelle verfügt über zwei Methoden: suspend() und resume(). Beide Methoden haben keine Parameter. Der Vertrag, der diese Schnittstelle umgibt, lautet: „suspend()“ und „resume()“ können beliebig oft aufgerufen werden, jedoch nicht, bevor die Komponente initialisiert und gestartet wurde oder nachdem die Komponente gestoppt und zerstört wurde. Der Aufruf der suspend()-Methode für eine angehaltene Komponente oder der Aufruf von resume() für eine bereits laufende Komponente hat keine Auswirkung.

Konfiguration
Dieser Satz von Schnittstellen beschreibt Konfigurationsüberlegungen. Wenn ein Problem auftritt, beispielsweise wenn das erforderliche Configuration-Element nicht vorhanden ist, kann eine ConfigurationException ausgelöst werden. Konfigurierbar
Komponenten, die ihr Verhalten basierend auf der Konfiguration bestimmen müssen, müssen diese Schnittstelle implementieren, um eine Instanz des Konfigurationsobjekts zu erhalten. Diese Schnittstelle verfügt über eine configure()-Methode mit nur einem Parameter vom Typ Configuration. Der diese Schnittstelle umgebende Vertrag sieht vor, dass die Methode configure() einmal während der Lebensdauer der Komponente aufgerufen wird. Das übergebene Konfigurationsobjekt darf nicht null sein.
Konfiguration
Konfigurationsobjekt ist ein Baum, der aus Konfigurationselementen besteht, die einige Eigenschaften haben. In gewisser Weise können Sie sich das Konfigurationsobjekt als stark vereinfachtes DOM vorstellen. Die Konfigurationsklasse enthält zu viele Methoden, die in diesem Artikel vorgestellt werden können. Weitere Informationen finden Sie in der JavaDoc-Dokumentation. Sie können einen String-, Int-, Long-, Float- oder Booleschen Wert vom Konfigurationsobjekt abrufen. Wenn die Konfiguration nicht vorhanden ist, wird ein Standardwert bereitgestellt. Das Gleiche gilt für Attribute. Sie können auch untergeordnete Konfigurationsobjekte abrufen. Der Vertrag besagt, dass ein Konfigurationsobjekt mit einem Wert keine untergeordneten Objekte haben sollte, und das Gleiche gilt für untergeordnete Objekte. Sie werden feststellen, dass Sie das übergeordnete Konfigurationsobjekt nicht abrufen können. Das ist es, was Design bewirkt. Um die Komplexität der Systemkonfiguration zu verringern, übergibt der Container in den meisten Fällen das untergeordnete Konfigurationsobjekt an die untergeordnete Komponente. Untergeordnete Komponenten sollten keinen Zugriff auf übergeordnete Konfigurationswerte haben. Dieser Ansatz kann einige Unannehmlichkeiten mit sich bringen, aber das Avalon-Team entscheidet sich immer dafür, die Sicherheit an die erste Stelle zu setzen, wenn Kompromisse erforderlich sind.
Rekonfigurierbar
Komponenten, die diese Schnittstelle implementieren, verhalten sich sehr ähnlich wie rekomponierbare Komponenten. Es gibt nur eine reconfigure()-Methode. Diese Entwurfsentscheidung besteht darin, die Lernschwierigkeit dieser Schnittstellen zu verringern, beginnend mit Re. Reconfigurable ist für Configurable das, was Recomposable für Composable ist.

Kontext
Das Konzept des Kontexts in Avalon entstand aus der Notwendigkeit eines Mechanismus zur Übergabe einfacher Objekte vom Container an die Komponente. Die genauen Protokoll- und Namensbindungen sind absichtlich undefiniert, um Entwicklern maximale Flexibilität zu bieten. Der Vertrag über die Verwendung von Kontextobjekten wird von Ihnen in Ihrem System definiert, obwohl die Mechanismen dieselben sind. Kontext
Kontextschnittstelle definiert nur eine get()-Methode. Es verfügt über einen Parameter vom Typ Objekt und gibt ein Objekt mit dem Parameter Objekt als Schlüsselwert zurück. Das Kontextobjekt wird vom Container zusammengestellt und dann an die Unterkomponente übergeben. Die Unterkomponente verfügt nur über Leseberechtigungen für den Kontext. Es gibt keinen anderen Vertrag, außer dass Context für untergeordnete Komponenten immer schreibgeschützt ist. Wenn Sie Avalons Kontext erweitern, achten Sie bitte darauf, diesen Vertrag einzuhalten. Es ist Teil des Reverse-Control-Modells und Teil des Sicherheitsdesigns. Darüber hinaus ist es aus demselben Grund, aus dem der Kontext schreibgeschützt sein sollte, nicht sinnvoll, einen Verweis auf den Container im Kontext zu übergeben.
Kontextualisierbar
Komponenten, die Kontextobjekte aus dem Container empfangen möchten, sollten diese Schnittstelle implementieren. Es verfügt über eine Methode namens contextualize() und der Parameter ist das vom Container zusammengestellte Context-Objekt. Der diese Schnittstelle umgebende Vertrag sieht vor, dass contextualize() einmal während der Lebensdauer der Komponente aufgerufen wird, nach LogEnabled, aber vor anderen Initialisierungsmethoden.
Rekontextualisierbar
Komponenten, die diese Schnittstelle implementieren, verhalten sich sehr ähnlich wie rekomponierbare Komponenten. Es gibt nur eine Methode namens recontextualize(). Diese Entwurfsentscheidung besteht darin, die Lernschwierigkeit von Schnittstellen zu verringern, die mit Re beginnen. Rekontextualisierbar ist kontextualisierbar, so wie Recomposable kontextualisierbar ist.
Resolvable
Die Resolvable-Schnittstelle wird verwendet, um Objekte zu identifizieren, die in bestimmten Kontexten aufgelöst werden müssen. Ein Beispiel ist: Ein Objekt wird von mehreren Kontextobjekten gemeinsam genutzt und ändert sein eigenes Verhalten entsprechend einem bestimmten Kontext. Der Kontext ruft die Methode „resolve()“ auf, bevor das Objekt zurückgegeben wird.

Logger
Jedes System muss in der Lage sein, Ereignisse zu protokollieren. Avalon verwendet sein LogKit-Projekt intern. Obwohl LogKit über einige Methoden für den statischen Zugriff auf eine Logger-Instanz verfügt, erwartet das Framework die Verwendung des Reverse-Control-Musters. LogEnabled
Jede Komponente, die eine Logger-Instanz erfordert, muss diese Schnittstelle implementieren. Diese Schnittstelle verfügt über eine Methode namens „enableLogging()“, die die Avalon Framework Logger-Instanz an die Komponente übergibt. Der Vertrag für diese Schnittstelle besteht darin, dass sie während der Lebensdauer der Komponente nur einmal vor allen anderen Initialisierungsschritten aufgerufen wird.
Logger
Die Logger-Schnittstelle wird zum Abstrahieren verschiedener Protokollbibliotheken verwendet. Es bietet eine einzigartige Client-API. Avalon Framework bietet drei Kapselungsklassen, die diese Schnittstelle implementieren: LogKitLogger für LogKit, Log4jLogger für Log4J und Jdk14Logger für den JDK1.4-Protokollierungsmechanismus.

Parameter
Avalon erkennt, dass die Konfigurationsobjekthierarchie in vielen Situationen zu schwergewichtig ist. Daher schlagen wir ein Parameters-Objekt vor, um eine Alternative zum Configuration-Objekt bereitzustellen und dabei einen Name-Wert-Paar-Ansatz zu verwenden. Parametrierbar
Jede Komponente, die Parameter anstelle von Konfigurationsobjekten verwenden möchte, implementiert diese Schnittstelle. Parametrisierbar hat nur eine Methode namens parametrize(), wobei der Parameter das Parameters-Objekt ist. Der Vertrag, der diese Schnittstelle umgibt, sieht vor, dass sie einmal während der Lebensdauer der Komponente aufgerufen wird. Diese Schnittstelle ist nicht mit der konfigurierbaren Schnittstelle kompatibel.
Parameter
Das Parameters-Objekt bietet einen Mechanismus zum Abrufen eines Werts über einen String-Typnamen. Es gibt praktische Methoden, mit denen Sie einen Standardwert verwenden können, wenn der Wert nicht vorhanden ist, oder Sie können einen beliebigen Wert im gleichen Format über die konfigurierbare Schnittstelle abrufen. Trotz der Ähnlichkeiten zwischen Parameters-Objekten und java.util.Property-Objekten gibt es wichtige semantische Unterschiede. Erstens sind Parameter schreibgeschützt. Zweitens können Parameter immer einfach aus dem Konfigurationsobjekt exportiert werden. Schließlich wird das Parameters-Objekt aus dem XML-Fragment exportiert und sieht folgendermaßen aus:

Thread
Thread-Tag-Marker sind Wird verwendet, um grundlegende semantische Informationen über den Container basierend auf der Komponentenverwendung zu signalisieren. Sie berücksichtigen die Thread-Sicherheit und stellen Tags für Komponentenimplementierungen bereit. Die beste Vorgehensweise besteht darin, die Implementierung dieser Schnittstellen bis zur Klasse zu verschieben, die die Komponente letztendlich implementiert. Dies vermeidet Komplikationen, wenn eine Komponente als ThreadSafe markiert ist, davon abgeleitete Komponentenimplementierungen jedoch nicht threadsicher sind. Die in diesem Paket definierten Schnittstellen sind Teil dessen, was wir die LifeStyle-Schnittstellenfamilie nennen. Eine weitere LifeStyle-Schnittstelle ist Teil des Excalibur-Pakets (also eine Erweiterung dieses Kernschnittstellensatzes). Poolable ist in der Pool-Implementierung von Excalibur definiert. SingleThreaded
Der Vertrag rund um die SingleThreaded-Komponente besagt, dass auf Komponenten, die diese Schnittstelle implementieren, nicht von mehreren Threads gleichzeitig zugegriffen werden darf. Jeder Thread muss über eine eigene Instanz dieser Komponente verfügen. Ein anderer Ansatz besteht darin, einen Komponentenpool zu verwenden, anstatt jedes Mal, wenn die Komponente angefordert wird, eine neue Instanz zu erstellen. Um einen Pool verwenden zu können, müssen Sie anstelle dieser Schnittstelle die Poolable-Schnittstelle von Avalon Excalibur implementieren.
ThreadSafe
Der Vertrag rund um ThreadSafe-Komponenten besteht darin, dass ihre Schnittstellen und Implementierungen normal funktionieren, unabhängig davon, wie viele Threads gleichzeitig auf die Komponente zugreifen. Obwohl dies ein flexibles Designziel ist, ist es je nach verwendeter Technologie manchmal einfach nicht erreichbar. Eine Komponente, die diese Schnittstelle implementiert, verfügt normalerweise nur über eine Instanz im System, und andere Komponenten verwenden diese Instanz.

Andere
Diese Klassen und Schnittstellen im Root-Paket des Avalon Framework umfassen die Exception-Hierarchie und einige allgemeine Dienstprogrammklassen. Aber es gibt eine Klasse, die es wert ist, erwähnt zu werden. Version
Die JavaTM-Versionstechnologie ist in der Manifestdatei im JAR-Paket angegeben. Das Problem besteht darin, dass Sie die Versionsinformationen verlieren, wenn das JAR entpackt wird, und die Versionsinformationen in einer leicht zu ändernden Textdatei abgelegt werden. Wenn diese Probleme mit einer steileren Lernkurve kombiniert werden, ist die Überprüfung der Versionen von Komponenten und Schnittstellen schwierig. Das Avalon-Entwicklungsteam hat das Versionsobjekt so entworfen, dass Sie Versionen einfach überprüfen und vergleichen können. Sie können das Versionsobjekt in Ihrer Komponente implementieren und es wird einfacher sein, die entsprechende Komponente oder Mindestversionsnummer zu testen.

Den Traum verwirklichen

Wir zeigen Ihnen, wie Sie Avalon Framework und Avalon Excalibur zur Implementierung Ihrer Serviceanwendung nutzen. Wir zeigen Ihnen, wie einfach Avalon zu bedienen ist.
Nach Abschluss der Analyse müssen Sie die Komponenten und Dienste erstellen, aus denen Ihr System besteht. Avalon würde nicht viel nützen, wenn es nur einige Programmiergewohnheiten beschreiben würde, die Sie verwenden könnten. Dennoch wird die Anwendung dieser Programmiergewohnheiten und -muster hilfreich sein, um das gesamte System zu verstehen. Avalon Excalibur bietet einige nützliche Komponenten und Tools, die Sie in Ihrem eigenen System verwenden können, um Ihnen das Leben zu erleichtern. Als Demonstration durchlaufen wir den gesamten Prozess der Definition einer Komponente und der Entnahme eines Dokuments aus einem Repository, um es zu implementieren. Wenn Sie sich an unsere Diskussion über den theoretischen Business-Server erinnern, haben wir diese Komponente als Dienst identifiziert. In tatsächlichen Situationen gibt es viele Situationen, in denen eine Komponente ein Dienst ist.

Implementierung der Komponente
Hier definieren wir, wie wir unsere Komponente implementieren. Wir werden den gesamten Prozess der Implementierung der zuvor erwähnten DocumentRepository-Komponente durchgehen. Als Erstes müssen wir herausfinden, auf welchen Bereich sich unsere Komponente konzentriert. Dann müssen wir herausfinden, wie wir unsere Komponenten erstellen und verwalten. Wählen Sie einen Schwerpunkt
Wir haben zuvor Rollen und Schnittstellen für die DocumentRepository-Komponente definiert und sind nun bereit, die Implementierung zu erstellen. Da die DocumentRepository-Schnittstelle nur eine Methode definiert, haben wir die Möglichkeit, eine threadsichere Komponente zu erstellen. Dies ist der beliebteste Komponententyp, da er nur einen minimalen Ressourcenverbrauch ermöglicht. Damit unsere Implementierung Thread-sicher ist, müssen wir wirklich sorgfältig darüber nachdenken, wie wir diese Komponente implementieren. Da alle unsere Dokumente in der Datenbank gespeichert sind und wir eine externe Guardian-Komponente verwenden möchten, müssen wir auf andere Komponenten zugreifen. Als verantwortungsbewusste Entwickler möchten wir Informationen protokollieren, die uns dabei helfen können, unsere Komponenten zu debuggen und zu verfolgen, was intern vor sich geht. Das Schöne am Avalon-Framework ist, dass Sie nur die Schnittstellen implementieren, die Sie benötigen, und diejenigen ignorieren können, die Sie nicht benötigen. Dies ist der Vorteil der Trennung von Belangen. Wenn Sie einen neuen Aspekt finden, der berücksichtigt werden muss, implementieren Sie einfach die entsprechende Schnittstelle, um der Komponente neue Funktionen hinzuzufügen. An den Teilen, die Ihre Komponente verwenden, sind keine Änderungen erforderlich. Da Thread-Sicherheit ein Designziel ist, wissen wir bereits, dass wir die ThreadSafe-Schnittstelle implementieren müssen. Die DocumentRepository-Schnittstelle verfügt nur über eine Methode, sodass die Verwendung der Arbeitsschnittstelle dieser Komponente diese Anforderung erfüllt. Und wir wissen, dass die Komponente nicht verwendet wird, bevor sie vollständig initialisiert ist, und auch nicht, nachdem sie zerstört wurde. Um den Entwurf zu vervollständigen, müssen wir einige implizite Schnittstellen implementieren. Wir möchten, dass die Lösung sicher genug ist, dass wir möglicherweise explizit wissen, ob eine Komponente vollständig initialisiert wurde. Um dieses Ziel zu erreichen, werden wir die Schnittstellen „Initialisierbar“ und „Einfügbar“ implementieren. Da sich Informationen über die Umgebung ändern können oder angepasst werden müssen, müssen wir das DocumentRepository die konfigurierbare Schnittstelle implementieren lassen. Die von Avalon bereitgestellte Methode zum Abrufen einer Instanz der erforderlichen Komponente ist die Verwendung eines ComponentManagers. Wir müssen die Composable-Schnittstelle implementieren, um Komponenteninstanzen von ComponentManager abzurufen. Da das DocumentRepository auf Dokumente in der Datenbank zugreift, müssen wir eine Entscheidung treffen. Möchten wir die Avalon Excalibur DataSourceComponent verwenden oder möchten wir den Datenbankverbindungsverwaltungscode selbst implementieren? In diesem Artikel verwenden wir DataSourceComponent. Zu diesem Zeitpunkt sieht unser Klassengerüst wie folgt aus: public class DatabaseDocumentRepositoryextends AbstractLogEnabledimplements DocumentRepository , Configurable, Composable, Initializable, Available, Component, ThreadSafe{ private boolean initialized = false; private ComponentManager manager = null; private String dbResource = null; /*** Konstrukteur. Alle Komponenten benötigen einen öffentlichen Konstruktor ohne Argumente *, um eine zulässige Komponente zu sein.*/ public DatabaseDocumentRepository() {} /*** Konfiguration. Beachten Sie, dass ich überprüfe, ob die Komponente * bereits konfiguriert wurde? Dies geschieht, um die Richtlinie durchzusetzen, dass „Configure“ nur einmal aufgerufen wird.*/ public final void configure(Configuration conf) throws ConfigurationException { if (initialized || disponiert) { throw new IllegalStateException ("Illegal call"); } if (null == this.dbResource) { this.dbResource = conf.getChild("dbpool").getValue(); getLogger().debug("Using Database Pool: " + this.dbResource ); // Beachten Sie, dass getLogger() von AbstractLogEnabled stammt, das ich für fast alle meine Komponenten erweitere. } } /*** Zusammensetzung. Beachten Sie, dass ich überprüfe, ob die Komponente * bereits initialisiert oder entsorgt wurde? Dies geschieht, um die Richtlinie einer ordnungsgemäßen Lebenszyklusverwaltung durchzusetzen.*/ public final void compose(ComponentManager cmanager) throws ComponentException { if (initialized || entsorgt) { throw new IllegalStateException ("Illegal call"); } if (null == this.manager) { this.manager = cmanager } } public final void initialize() throws Exception { if (null == this. manager) { throw new IllegalStateException("Not Composed"); } if (null == this.dbResource) { throw new IllegalStateException("NotConfiged"); .initialized = true; } public final void dispose() { this.disposed = true; this.dbResource = null } public final Document getDocument(Principal requestor, int refId) { if (!initialized || entsorgt) { throw new IllegalStateException("Illegal call"); } // TODO: FILL IN LOGIC }}
Sie können einige Strukturmuster im obigen Code finden. Wenn Sie beim Entwerfen auf Sicherheit achten, sollten Sie jeden Vertrag in Ihrer Komponente explizit durchsetzen. Sicherheit ist nur so stark wie ihr schwächstes Glied. Verwenden Sie eine Komponente nur, wenn Sie sicher sind, dass sie vollständig initialisiert wurde. Verwenden Sie sie nach ihrer Zerstörung nie wieder. Ich habe diese Logik hier eingefügt, weil Sie es genauso machen würden, wenn Sie Ihre eigenen Klassen schreiben.
Komponenteninstanziierung und Verwaltungskomponenten
Damit Sie verstehen, wie die Container-/Komponentenbeziehung funktioniert, besprechen wir zunächst die manuelle Art der Komponentenverwaltung. Als Nächstes besprechen wir, wie die Excalibur-Komponentenarchitektur von Avalon die Komplexität vor Ihnen verbirgt. Es kommt immer noch vor, dass Sie die Komponenten lieber selbst verwalten möchten. Meistens verfügt Excalibur jedoch über die Leistung und Flexibilität, um Ihre Anforderungen zu erfüllen. Die manuelle Methode
Alle Komponenten von Avalon werden irgendwo erstellt. Der Code, der die Komponente erstellt, ist der Container für die Komponente. Der Container ist für die Verwaltung des Lebenszyklus der Komponenten vom Bau bis zur Zerstörung verantwortlich. Der Container kann eine statische „Main“-Methode haben, die über die Befehlszeile aufgerufen werden kann, oder es kann sich um einen anderen Container handeln. Denken Sie bei der Gestaltung Ihres Containers an das Muster der Rückwärtssteuerung. Informationen und Methodenaufrufe fließen nur vom Container zur Komponente. Subversion of Control
Subversion of Control ist das Antimuster der umgekehrten Kontrolle. Subversion-Kontrolle wird erreicht, wenn Sie einen Verweis auf einen Container an eine Komponente übergeben. Dies ist auch der Fall, wenn Sie einer Komponente die Verwaltung ihres eigenen Lebenszyklus überlassen. Code, der auf diese Weise funktioniert, sollte als fehlerhaft betrachtet werden. Wenn Sie Container-/Komponentenbeziehungen mischen, erschweren deren Interaktionen das Debuggen und Überwachen des Systems aus Sicherheitsgründen.
Um untergeordnete Komponenten verwalten zu können, müssen Sie während ihrer gesamten Lebensdauer Verweise auf diese beibehalten. Bevor der Container und andere Komponenten die Unterkomponente verwenden können, muss die Initialisierung abgeschlossen werden. Für unser DocumentRepository könnte der Code so aussehen: class ContainerComponent implementiert Component, Initializable, Following{ DocumentRepository docs = new DatabaseDocumentRepository(); DefaultComponentManager manager = new DefaultComponentManager(); Ausnahme { Logger docLogger = new LogKitLogger( Hierarchy.defaultHierarchy() .getLoggerFor( "document" ) ); this.docs.enableLogging( docLogger.childLogger( "repository" ) ); this.guard.enableLogging( docLogger .childLogger( "security " ) ); DefaultConfiguration pool = new DefaultConfiguration("dbpool"); pool.setValue("main-pool"); DefaultConfiguration conf = new DefaultConfiguration(""); conf.addChild(pool); this. manager.addComponent( DocumentRepository .ROLE, this.docs ); this.manager.addComponent( GuardianComponent.ROLE, this.guard ); this.guard.compose( this.docs.configure ); (conf); this.guard.initialize(); this.docs.initialize(); public void dispose();
Für die Der Kürze halber habe ich die explizite Prüfung aus dem obigen Code entfernt. Sie sehen, dass das manuelle Erstellen und Verwalten von Komponenten eine detaillierte Aufgabe ist. Wenn Sie einen Schritt im Komponentenlebenszyklus vergessen, werden Sie auf Fehler stoßen. Dies erfordert auch fundierte Kenntnisse der Komponente, die Sie instanziieren. Ein anderer Ansatz besteht darin, der oben genannten ContainerComponent einige Methoden hinzuzufügen, um die Initialisierung der Komponente dynamisch zu handhaben.
Automatisierte Autonomie
Entwickler sind von Natur aus faul und verbringen daher ihre Zeit damit, einen speziellen ComponentManager zu schreiben, der als Container für alle Komponenten im System fungiert. Auf diese Weise müssen sie kein tiefes Verständnis der Schnittstellen aller Komponenten im System haben. Dies kann eine frustrierende Aufgabe sein. Die Entwickler von Avalon haben ein solches Biest geschaffen. Die Komponentenarchitektur von Avalon Excalibur umfasst einen ComponentManager, der über XML-Konfigurationsdateien gesteuert wird. Es gibt einen Kompromiss, wenn Sie die Verantwortung für die Verwaltung von Komponenten an den ComponentManager von Excalibur übergeben. Sie geben die Feinkontrolle darüber auf, welche Komponenten im CompomentManager enthalten sind. Wenn Ihr System jedoch ziemlich groß ist, kann die manuelle Steuerung für Sie ein frustrierendes Unterfangen sein. In diesem Fall ist es aus Gründen der Systemstabilität am besten, alle Komponenten im System zentral von einem Ort aus zu verwalten. Da es bei der Komponentenarchitektur von Excalibur verschiedene Integrationsebenen gibt, beginnen wir mit der niedrigsten Ebene. Excalibur verfügt über eine Reihe von ComponentHandler-Objekten, die als unabhängige Container für jeden Komponententyp dienen. Sie verwalten den gesamten Lebenszyklus Ihrer Komponenten. Lassen Sie uns das Konzept der Lifestyle-Schnittstellen vorstellen. Eine Survival-Schnittstelle beschreibt, wie das System mit einer Komponente umgeht. Da die Art und Weise, wie Komponenten funktionieren, Auswirkungen auf den Systembetrieb hat, müssen wir die Auswirkungen einiger aktueller Lebensweisen diskutieren: · org.apache.avalon.framework.thread.SingleThreadedo ist nicht threadsicher oder wiederverwendbar. o Wenn keine andere Survival-Modus-Schnittstelle angegeben ist, berücksichtigt das System diese. o Jedes Mal, wenn eine Komponente angefordert wird, wird eine brandneue Instanz erstellt. o Instanzerstellung und -initialisierung werden verschoben, bis die Komponente angefordert wird. · Die Komponente org.apache.avalon.framework.thread.Threadsafeo ist vollständig wiedereintrittsfähig und entspricht allen Thread-Sicherheitsprinzipien. o Das System erstellt eine Instanz und der Zugriff darauf wird von allen Composable-Komponenten gemeinsam genutzt. o Die Erstellung und Initialisierung der Instanz ist abgeschlossen, wenn der ComponentHandler erstellt wird. · org.apache.avalon.excalibur.pool.Poolableo ist nicht threadsicher, aber vollständig wiederverwendbar. o Erstellen Sie eine Reihe von Instanzen und fügen Sie sie in den Pool ein. Wenn die Composable-Komponente dies anfordert, stellt das System eine verfügbare Instanz bereit. o Die Erstellung und Initialisierung der Instanz ist abgeschlossen, wenn der ComponentHandler erstellt wird. Die ComponentHandler-Schnittstelle ist sehr einfach zu handhaben. Sie initialisieren den Konstruktor über Java-Klassen, Konfigurationsobjekte, ComponentManager-Objekte, Kontextobjekte und RoleManager-Objekte. Wenn Sie wissen, dass Ihre Komponente keines der oben genannten Elemente benötigt, können Sie stattdessen eine Null hochladen. Wenn Sie anschließend einen Verweis auf die Komponente benötigen, rufen Sie die Methode „get“ auf. Wenn Sie fertig sind, rufen Sie die Methode „put“ auf, um die Komponente an den ComponentHandler zurückzugeben. Der folgende Code erleichtert uns das Verständnis. class ContainerComponent implementiert Component, Initializable, Following{ ComponentHandler guard = null; DefaultComponentManager manager = new DefaultComponentManager(); "main-pool"); DefaultConfiguration conf = new DefaultConfiguration(""); this.docs.configure(conf); , null, null); this.guard = ComponentHandler.getComponentHandler( DocumentGuardianComponent.class, null, this.manager, null, null); Logger docLogger = new LogKitLogger( Hierarchy.defaultHierarchy() .getLoggerFor( "document" ) ); .docs.enableLogging( docLogger.childLogger( "repository" ) ); this.guard.enableLogging( docLogger.childLogger( "security" ) ); this.manager.addComponent(DocumentRepository.ROLE, this.docs); addComponent(GuardianComponent.ROLE, this.guard); this.docs.initialize(); public void dispose() { this.docs.dispose(); }}
Hier haben wir nur ein paar Codezeilen vermisst. Wir haben das Konfigurationsobjekt immer noch manuell erstellt, den Logger eingerichtet und mussten trotzdem das ComponentHandler-Objekt initialisieren und zerstören. Was wir hier tun, besteht lediglich darin, zu verhindern, dass es von Schnittstellenänderungen betroffen wird. Es kann für Sie von Vorteil sein, auf diese Weise zu programmieren. Excalibur geht noch einen Schritt weiter. Die meisten komplexen Systeme verfügen über einige Konfigurationsdateien. Sie ermöglichen Administratoren, wichtige Konfigurationsinformationen anzupassen. Excalibur kann Konfigurationsdateien in den folgenden Formaten lesen und daraus Systemkomponenten erstellen. " class="org.apache.avalon.excalibur.datasource.JdbcDataSource"> false < ;driver>org.gjt.mm.mysql.Driver test < ;/component-instance> false org.gjt.mm.mysql.Driver jdbc:mysql:localhost/myotherdb test test documents security Sie möchten angegeben werden. Sie werden feststellen, dass wir bereits einige Komponenten definiert haben. Wir haben die bekannten Klassen DocumentRepository und GuardianComponent sowie einige Excalibur DataSourceComponent-Klassen. Darüber hinaus haben wir jetzt einige spezifische Konfigurationsinformationen für die Guardian-Komponente. Um diese Systeme in Ihr System einzulesen, bietet Ihnen das Avalon-Framework einige Annehmlichkeiten: DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();Configuration systemConf = builder.buildFromFile("/path/to/file.xconf"); Es vereinfacht unseren bisherigen Code zum manuellen Erstellen von Konfigurationselementen und schränkt die Informationen ein, die wir beim Programmieren explizit kennen müssen. Werfen wir noch einmal einen Blick auf die Container-Klasse, um zu sehen, ob wir wirklich etwas gespeichert haben. Denken Sie daran, dass wir 5 Komponenten (der ComponentSelector zählt als eine Komponente) und die Konfigurationsinformationen für jede Komponente angegeben haben. Klasse ContainerComponent implementiert Komponente, Initialisierbar, Einweg { ExcaliburComponentManager manager = new ExcaliburComponentManager(); public void initialize() throws Exception { DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); Configuration sysConfig = builder.buildFromFile("./conf/system.xconf") ; this.manager.setLogger( Hierarchy.getDefaultHierarchy() .getLoggerFor("document") ); this.manager.contextualize( new DefaultContext() ); } public void dispose() { this.manager.dispose(); }}
Ist das nicht erstaunlich? Wir haben mehr als die doppelte Anzahl an Komponenten mit mehr als der doppelten Menge an Code initialisiert (6 Codezeilen statt 13). Diese Konfigurationsdatei hat einen Nachteil: Sie sieht etwas verrückt aus, minimiert jedoch die Menge an Code, die geschrieben werden muss. Hinter den Kulissen von ExcaliburComponentManager ist viel los. Für jedes „Komponenten“-Element in der Konfigurationsdatei erstellt Excalibur einen ComponentHandler für jeden Klasseneintrag und stellt eine entsprechende Beziehung mit der Rolle her. Das „component“-Element und alle seine untergeordneten Elemente sind Konfigurationen für die Komponente. Wenn es sich bei der Komponente um einen ExcaliburComponentSelector handelt, liest Excalibur jedes „Komponenteninstanz“-Element und führt die gleiche Art von Operation wie zuvor aus, wobei diesmal eine entsprechende Beziehung mit dem Hinweiseintrag hergestellt wird. Sorgen Sie dafür, dass die Konfigurationsdatei besser aussieht
Wir können Aliase verwenden, um das Erscheinungsbild der Konfigurationsdatei zu ändern. Excalibur verwendet einen RoleManager, um Aliase für das Konfigurationssystem bereitzustellen. RoleManager kann eine Klasse sein, die Sie speziell erstellen, oder Sie können DefaultRoleManager verwenden und ein Konfigurationsobjekt übergeben. Wenn ich DefaultRoleManager verwende, verstecke ich die Rollenkonfigurationsdatei und andere Teile des Systems in einer JAR-Datei. Dies liegt daran, dass Charakterprofile nur von Entwicklern geändert werden. Das Folgende ist die RoleManager-Schnittstelle: interface RoleManager{ String getRoleForName( String shorthandName ); String getDefaultClassNameForRole( String role ); String getDefaultClassNameForHint( String hint, String shorthand );}
Schauen wir uns an, wie Excalibur in unserem Framework verwendet wird Rollenmanager. Zunächst durchläuft Excalibur alle untergeordneten Elemente des Stammelements. Dies umfasst alle „Komponenten“-Elemente, aber dieses Mal erkennt Excalibur den Elementnamen nicht, sondern fragt den RoleManager, welche Rolle wir für diese Komponente verwenden werden. Wenn RoleManager null zurückgibt, werden das Element und alle seine untergeordneten Elemente ignoriert. Als nächstes leitet Excalibur den Klassennamen vom Rollennamen ab. Der letzte Ansatz besteht darin, Klassennamen dynamisch Untertypen von ComponentSelector zuzuordnen. Excalibur bietet eine Standardimplementierung von RoleManager, die eine XML-Konfigurationsdatei verwendet. Tags sind ziemlich einfach und verbergen alle zusätzlichen Informationen, die Administratoren nicht sehen sollen. hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSourceComponent"/> org.apache.bizserver.docs.GuardianComponent" shorthand="guardian" default-class="org.apache.bizserver.docs.DocumentGuardianComponent"/>
Um RoleManager verwenden zu können, müssen Sie Sie müssen die Methode „Initialisierung“ in der Containerklasse ändern. Sie verwenden den Konfigurations-Builder, um aus dieser Datei einen Konfigurationsbaum zu erstellen. Denken Sie daran: Wenn Sie einen RoleManager verwenden möchten, müssen Sie die Methode „setRoleManager“ aufrufen, bevor Sie die Methode „configure“ aufrufen. Um zu zeigen, wie Sie diese XML-Datei vom Klassenlader erhalten können, zeige ich die folgende Technik: DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();Configuration sysConfig = builder.buildFromFile("./conf/system.xconf");Configuration RoleConfig = builder.build( this.getClass().getClassLoader() .getResourceAsStream("/org/apache/bizserver/docs/document.roles"));DefaultRoleManager Roles = new DefaultRoleManager();roles.enableLogging(Hierarchy.getDefaultHierarchy () .getLoggerFor("document.roles"));roles.configure(roleConfig);this.manager.setLogger( Hierarchy.getDefaultHierarchy() .getLoggerFor("document") );this.manager.contextualize( new DefaultContext() ); this.manager.setRoleManager( Roles );this.manager.configure( sysConfig );this.manager.initialize();
Nachdem wir nun 6 Codezeilen hinzugefügt haben, werfen wir einen Blick auf die Vorteile, die es mit sich bringt. Unsere endgültige Konfigurationsdatei kann wie folgt geschrieben werden: auto -commit>false org.gjt.mm.mysql.Driver jdbc:mysql:localhost/mydb test test false org.gjt.mm.mysql.Driver jdbc:mysql:localhost/myotherdb passwort>test Policy file="/home/system/document.policy"/> Wie Sie sehen, ist diese Datei viel besser lesbar als die vorherige Datei. Jetzt können wir dem System beliebig viele Komponenten hinzufügen, ohne mehr Code zu deren Unterstützung schreiben zu müssen.

Verwenden der Komponente
Nachdem wir nun unsere Komponenten erstellt haben, werden wir sie verwenden. Unabhängig davon, wie die Komponente initialisiert und verwaltet wird, ist die Art und Weise, wie Sie auf die Komponente zugreifen, dieselbe. Sie müssen die Composable-Schnittstelle implementieren, um eine Referenz vom ComponentManager zu erhalten. Der ComponentManager enthält Verweise auf alle Komponenten, die Sie benötigen. Der Einfachheit halber gehen wir davon aus, dass der ComponentManager, den wir erhalten, gemäß der endgültigen Konfigurationsdatei im vorherigen Abschnitt konfiguriert ist. Das bedeutet, dass wir ein Repository, einen Guardian und zwei DataSources haben. Grundsätze für die Verwendung der Komponentenverwaltungsinfrastruktur
Die Komponentenverwaltungsinfrastruktur erfordert, dass Sie die Komponenten freigeben, auf die Sie Verweise erhalten. Der Grund für diese Einschränkung liegt in der ordnungsgemäßen Verwaltung der Komponentenressourcen. Der ComponentManager wurde unter Berücksichtigung der Tatsache entwickelt, dass Sie über verschiedene Arten von Komponenten für bestimmte Rollen verfügen. Ein weiterer einzigartiger Aspekt von ComponentSelector besteht darin, dass er auch als Komponente konzipiert ist. Dadurch können wir einen ComponentSelector von einem ComponentManager abrufen. Es gibt zwei legale Möglichkeiten, mit Verweisen auf externe Komponenten umzugehen. Sie können Referenzen während der Initialisierung abrufen und diese bei der Zerstörung freigeben. Sie können den Code, der Komponenten verarbeitet, auch in try/catch/finally-Blöcken einfügen. Beide Methoden haben Vor- und Nachteile. Initialisierungs- und Entsorgungsansatz
class MyClass implementiert Component, Composable, Einweg{ ComponentManager manager;*** Rufen Sie einen Verweis auf einen Guard ab und behalten Sie den Verweis auf * den ComponentManager bei.*/ public void compose(ComponentManager manager) throws ComponentException { if (this.manager == null) { this.manager = manager; myGuard = (Guardian) this.manager.lookup(Guardian.ROLE); } } /*** Dies ist die Methode, die den Guardian verwendet.*/ public void myMethod() throws SecurityException { this.myGuard.checkPermission(new BasicPermission(" test")); } /*** Entfernen Sie unsere Referenzen*/ public void dispose() { this.manager.release(this.myGuard); this.myGuard = null; this.manager = null; }}
Aus dem Beispiel Wie Sie dem Code entnehmen können, ist dies einfach. Wenn das Objekt zum ersten Mal den ComponentManager empfängt, erhält es einen Verweis auf die Guardian-Komponente. Wenn Sie sicherstellen können, dass die Guardian-Komponente threadsicher ist (die ThreadSafe-Schnittstelle implementiert), müssen Sie nur diese Dinge tun. Leider können Sie dies auf Dauer nicht garantieren. Um Ressourcen korrekt zu verwalten, müssen wir den Verweis auf die Komponente freigeben, nachdem wir damit fertig sind. Deshalb behalten wir einen Verweis auf den ComponentManager bei. Der Hauptnachteil dieses Ansatzes liegt beim Umgang mit Komponenten in einem Komponentenpool. Ein Verweis auf eine Komponente hält die Komponente am Leben. Wenn das Objekt eine kurze Lebensdauer hat, stellt dies möglicherweise kein Problem dar. Wenn das Objekt jedoch eine von der Excalibur-Komponentenverwaltungsarchitektur verwaltete Komponente ist, bleibt seine Lebensdauer bestehen, solange Verweise darauf vorhanden sind. Das bedeutet, dass wir den Komponentenpool tatsächlich in eine Komponentenfabrik verwandeln. Der Hauptvorteil dieses Ansatzes besteht darin, dass der Code zum Abrufen und Freigeben der Komponente klar ist. Sie müssen den Ausnahmebehandlungscode nicht verstehen. Ein weiterer subtiler Unterschied besteht darin, dass Sie die Existenz des Wächters mit der Fähigkeit verknüpfen, dieses Objekt zu initialisieren. Sobald während der Initialisierungsphase eines Objekts eine Ausnahme ausgelöst wird, müssen Sie davon ausgehen, dass das Objekt kein gültiges Objekt ist. Manchmal möchten Sie, dass das Programm fehlschlägt, wenn die erforderliche Komponente nicht vorhanden ist. Dann ist dies kein Problem. Beim Entwerfen von Komponenten müssen Sie sich dieser impliziten Bedeutung wirklich bewusst sein.
Ausnahmebehandlungsansatz
Klasse MyClass implementiert Composable, Einweg{ ComponentManager manager; /*** Rufen Sie einen Verweis auf einen Guard ab und behalten Sie den Verweis auf * den ComponentManager bei.*/ public void compose(ComponentManager manager) throws ComponentException { if (this.manager == null) { this.manager = manager; } } /*** Dies ist die Methode, die den Wächter erhält.*/ public void myMethod() throws SecurityException { Guardian myGuard = null; myGuard = (Guardian) this.manager.lookup(Guardian.criticalSection(myGuard) ; } Catch (ComponentException ce) { throw new SecurityException(ce.getMessage() } Catch (SecurityException se) { if (myGuard != null) { this.manager.release(myGuard); } } /*** Führen Sie einen kritischen Teil des Codes aus.*/ public void CriticalSection(Guardian myGuard) throws SecurityException { myGuard.checkPermission(new BasicPermission("test") }}
Wie Sie sehen, ist dieser Code etwas komplex. Um es zu verstehen, müssen Sie die Ausnahmebehandlung verstehen. Dies stellt möglicherweise kein Problem dar, da die überwiegende Mehrheit der Java-Entwickler weiß, wie man mit Ausnahmen umgeht. Auf diese Weise müssen Sie sich nicht zu viele Gedanken über die Lebensdauer der Komponente machen, da sie freigegeben wird, sobald wir sie nicht mehr benötigen. Der Hauptnachteil dieses Ansatzes ist die Hinzufügung von Ausnahmebehandlungscode, der komplexer ist. Um die Komplexität zu minimieren und die Wartung des Codes zu vereinfachen, extrahieren wir den Arbeitscode und fügen ihn in eine andere Methode ein. Bitte denken Sie daran, dass wir im try-Block so viele Verweise auf die Komponente erhalten können, wie wir möchten. Der Hauptvorteil dieses Ansatzes besteht darin, dass Sie Komponentenreferenzen effizienter verwalten können. Ebenso gibt es keinen wirklichen Unterschied, wenn Sie ThreadSafe-Komponenten verwenden, wenn Sie jedoch Komponenten aus dem Komponentenpool verwenden, gibt es einen Unterschied. Das Abrufen eines neuen Verweises auf eine Komponente bei jeder Verwendung ist zwar mit einem leichten Mehraufwand verbunden, aber die Wahrscheinlichkeit, gezwungen zu sein, eine neue Komponenteninstanz zu erstellen, ist deutlich geringer. Ebenso wie die Art und Weise, wie Initialisierung und Zerstörung funktionieren, gibt es einen subtilen Unterschied, den Sie verstehen müssen. Die Ausnahmebehandlung erfolgt so, dass das Programm während der Initialisierung nicht fehlschlägt, wenn der Manager die Komponente nicht finden kann. Wie bereits erwähnt, ist dies nicht ganz unbegründet. Oftmals gehen Sie davon aus, dass eine bestimmte Komponente vorhanden ist, aber das Programm muss nicht fehlschlagen, wenn die erwartete Komponente nicht vorhanden ist.

Eine Komponente von einem ComponentSelector abrufen
Für die meisten Vorgänge müssen Sie lediglich den ComponentManager verwenden. Nachdem wir nun entschieden haben, dass wir mehrere Instanzen von DataSourceComponent benötigen, müssen wir wissen, wie wir die gewünschte Instanz erhalten. ComponentSelector ist etwas komplizierter als ComponentManagers, da es Hinweise gibt, um während der Verarbeitung die gewünschte Referenz zu erhalten. Eine Komponente gehört zu einer bestimmten Rolle, wie wir bereits deutlich gemacht haben. Manchmal müssen wir jedoch eine aus mehreren Komponenten eines Charakters auswählen. ComponentSelector verwendet ein beliebiges Objekt als Hinweis. Meistens ist dieses Objekt ein String, obwohl Sie möglicherweise ein Locale-Objekt verwenden möchten, um eine korrekt internationalisierte Komponente zu erhalten. In dem von uns eingerichteten System verwenden wir eine Zeichenfolge, um die richtige Instanz von DataSourceComponent auszuwählen. Wir haben uns sogar ein Konfigurationselement gegeben, um anzugeben, welche Zeichenfolge benötigt wird, um die richtige Komponente zu erhalten. Diese Vorgehensweise empfiehlt sich, da sie die Systemverwaltung erleichtert. Dies macht es für Systemadministratoren einfacher, Verweise auf andere Komponenten zu sehen, als sich diese magischen Konfigurationswerte merken zu müssen. Vom Konzept her gibt es keinen Unterschied zwischen dem Abrufen einer Komponente von einem ComponentSelector und dem Abrufen einer Komponente von einem ComponentManager. Sie haben nur noch einen Schritt. Denken Sie daran, dass ComponentSelector auch eine Komponente ist. Wenn Sie die Rolle des ComponentSelect nachschlagen, bereitet der ComponentManager die ComponentSelector-Komponente vor und sendet sie an Sie zurück. Dann müssen Sie die Komponente darüber auswählen. Um dies zu veranschaulichen, werde ich den zuvor besprochenen Ausnahmebehandlungscode erweitern. public void myMethod() throws Exception{ ComponentSelector dbSelector = null; DataSourceComponent datasource = null; try { dbSelector = (ComponentSelector) this.manager.lookup(DataSourceComponent.ROLE + "Selector"); .useDb); this.process(datasource.getConnection()); } Catch (Exception e) { throw e } Finally { if (datasource != null) { dbSelector.release(datasource); ) { this.manager.release(dbSelector); } }}
Sie können sehen, dass wir durch die Verwendung der Rolle der angegebenen Komponente einen Verweis auf den ComponentSelector erhalten haben. Wir folgten der zuvor erwähnten Rollenbenennungskonvention und fügten „Selektor“ als Suffix zum Rollennamen hinzu. Sie können eine statische Schnittstelle verwenden, um alle Rollennamen im System zu verarbeiten und so die Anzahl der Zeichenfolgenverkettungen in Ihrem Code zu reduzieren. Es ist auch völlig akzeptabel, dies zu tun. Als nächstes müssen wir einen Verweis auf die DataSource-Komponente vom ComponentSelector erhalten. Unser Beispielcode geht davon aus, dass wir die erforderlichen Informationen vom Konfigurationsobjekt erhalten und in einer Klassenvariablen namens „useDb“ abgelegt haben.

Werkzeugklassen von Excalibur
Der letzte Abschnitt stellt Ihnen verschiedene Arten von Komponenten und Werkzeugen vor, die von Apache Avalon Excalibur bereitgestellt werden. Diese Werkzeugklassen sind robust und können in tatsächlichen Produktionssystemen verwendet werden. Wir haben ein informelles hierarchisches Projekt namens „Scratchpad“, in dem wir die Implementierungsdetails potenzieller neuer Werkzeugklassen erarbeiten. Die Qualität der Tools in Scratchpad variiert und es gibt keine Garantie dafür, dass sie auf die gleiche Weise verwendet werden, obwohl Sie sie möglicherweise nützlich finden. Command Line Interface (CLI)
Die CLI-Toolklasse wird in einigen Projekten, einschließlich Avalon Phoenix und Apache Cocoon, zum Verarbeiten von Befehlszeilenparametern verwendet. Es bietet einen Mechanismus zum Drucken von Hilfeinformationen und kann Parameteroptionen in Form von Kurz- oder Langnamen verarbeiten.
Sammelwerkzeugklasse
Sammlungsdienstprogrammklassen bieten einige Verbesserungen der JavaTM Collections API. Zu diesen Verbesserungen gehören die Möglichkeit, Schnittmengen zwischen zwei Listen und eine PriorityQueue zu finden, eine Erweiterung von Stack, die es ermöglicht, Objektprioritätsänderungen in einem einfachen First-In-Last-Out-Stack zu implementieren.
Komponentenverwaltung
Wir haben diesen Aspekt der Nutzung bereits früher besprochen. Dies ist das komplexeste Monster in Excalibur, bietet jedoch in nur wenigen Klassen eine Menge Funktionalität. Neben den einfachen SingleThreaded- oder ThreadSafe-Verwaltungstypen gibt es auch einen Poolable-Typ. Wenn eine Komponente die Poolable-Schnittstelle von Excalibur anstelle der SingleThreaded-Schnittstelle implementiert, verwaltet sie einen Pool von Komponenten und verwendet Instanzen wieder. Meistens funktioniert das gut. Für den Fall, dass einige Komponenten nicht wiederverwendet werden können, wird die SingleThreaded-Schnittstelle verwendet.
LogKit-Verwaltung
Das Avalon-Entwicklungsteam erkannte, dass viele Menschen einen einfachen Mechanismus zum Erstellen komplexer Protokollzielhierarchien benötigten. Basierend auf ähnlichen Ideen wie RoleManager entwickelte das Team LogKitManager, der vom zuvor erwähnten Excalibur Component Management-System verwendet werden kann. Basierend auf dem „logger“-Attribut werden entsprechende Logger-Objekte für verschiedene Komponenten bereitgestellt.
Threading-Tool-Klassen
Das Concurrent-Paket bietet einige Klassen zur Unterstützung der Multithread-Programmierung: Lock (Implementierung von Mutex), DjikstraSemaphore, ConditionalEvent und ThreadBarrier.
Dies basiert auf javax.sql .DataSource-Klassendesign, aber vereinfacht. Es gibt zwei Implementierungen von DataSourceComponent: eine, die explizit den JDBC-Verbindungspool verwendet, und die andere, die die Klasse javax.sql.DataSource des J2EE-Anwendungsservers verwendet.
Eingabe-/Ausgabe-Dienstprogrammklasse (IO)
Die IO-Dienstprogrammklasse stellt einige FileFilter-Klassen sowie datei- und IO-bezogene Dienstprogrammklassen bereit.
Pool-Implementierung
Pool implementiert einen Pool, der in verschiedenen Situationen verwendet werden kann. Eine der Implementierungen ist sehr schnell, kann aber nur in einem Thread verwendet werden. Es ist gut, den FlyWeight-Modus zu implementieren. Es gibt auch einen DefaultPool, der die Anzahl der Objekte im Pool nicht verwaltet. SoftResourceManagingPool ermittelt, ob ein Schwellenwert überschritten wird, wenn das Objekt zurückgegeben wird. Wenn dieser überschritten wird, wird das Objekt „zurückgezogen“. Schließlich löst HardResourceManagingPool eine Ausnahme aus, wenn Sie die maximale Anzahl von Objekten erreichen. Die letzten drei Pools sind alle ThreadSafe.
Property-Dienstprogrammklasse
Property-Dienstprogrammklasse wird zusammen mit dem Kontextobjekt verwendet. Sie ermöglichen die Erweiterung von „Variablen“ in einem auflösbaren Objekt. So funktioniert es: „${resource}“ sucht im Kontext nach einem Wert namens „resource“ und ersetzt das Symbol durch diesen Wert.

Fazit

Avalon hat den Test der Zeit bestanden und ist für Sie einsatzbereit. Die in diesem Abschnitt bereitgestellten Beweise können Ihnen und anderen dabei helfen, sich selbst und andere davon zu überzeugen, dass die Verwendung eines etablierten Frameworks besser ist, als selbst eines zu erstellen.
Vielleicht sind Sie bereits überzeugt, benötigen aber Hilfe dabei, Ihre Kollegen davon zu überzeugen, dass Avalon die richtige Wahl ist. Vielleicht müssen Sie sich auch selbst überzeugen. Unabhängig davon wird Ihnen dieses Kapitel dabei helfen, Ihre Gedanken zu ordnen und überzeugende Beweise zu liefern. Wir müssen die Angst, Unsicherheit und Zweifel (FUD) des Open-Source-Modells bekämpfen. Was die Beweise für die Wirksamkeit von Open Source betrifft, empfehle ich die Lektüre von Eric S. Raymonds hervorragender Behandlung des Themas N400017. Was auch immer Sie von seinen Ansichten halten, seine Artikel sind in einem Buch mit dem Titel „The Cathedral and the Bazaar“ zusammengefasst, um Werbung zu machen Akzeptanz von Open Source im Allgemeinen.

Avalon funktioniert
Unser Fazit ist, dass Avalon das erreicht, wofür es ursprünglich entwickelt wurde. Anstatt neue Konzepte und Ideen einzuführen, verwendet Avalon einige bewährte Konzepte und standardisiert sie. Das neueste Konzept, das das Avalon-Design beeinflusst, ist das Separation of Concerns-Muster, das um 1995 vorgeschlagen wurde. Schon damals war die Trennung von Überlegungen ein formalisierter Ansatz für Systemanalysetechniken. Die Benutzerbasis von Avalon liegt bei Hunderten. Einige Projekte wie Apache Cocoon, Apache JAMES und Jesktop basieren auf Avalon. Die Entwickler dieser Projekte sind Benutzer des Avalon Framework. Da Avalon eine so große Anzahl an Benutzern hat, ist es gut getestet. Entworfen von den Besten
Die Autoren von Avalon sind sich bewusst, dass wir nicht die einzige Expertengruppe für serverseitiges Computing sind. Wir haben Konzepte und Ideen aus der Forschung anderer Leute verwendet. Wir reagieren auf das Feedback unserer Benutzer. Avalon wurde nicht nur von den fünf oben genannten Entwicklern entworfen, sie brachten auch die Ideen der Rückwärtssteuerung, Trennungsüberlegungen und komponentenorientierte Programmierung mit und entwarfen es. Das Tolle an Open Source ist, dass die Ergebnisse eine Verschmelzung der besten Ideen und des besten Codes sind. Avalon durchlief eine Phase des Testens von Ideen und der Ablehnung einiger, weil es bessere Lösungen gab. Sie können die Erkenntnisse des Avalon-Entwicklungsteams nutzen und auf Ihre eigenen Systeme anwenden. Sie können die vordefinierten Komponenten in Excalibur in Ihren eigenen Projekten verwenden und sie wurden auf eine fehlerfreie Ausführung unter hoher Last getestet.
Kompatibilitätslizenz
Die Apache Software License (ASL) ist mit jeder anderen bekannten Lizenz kompatibel. Die größten bekannten Ausnahmen sind die GNU Public License (GPL) und die Lesser GNU Public License (LGPL). Wichtig ist, dass ASL für die gemeinsame Entwicklung recht freundlich ist und Sie nicht dazu zwingt, Quellcode freizugeben, wenn Sie dies nicht möchten Zu. Der hoch angesehene HTTP-Server der Apache Software Foundation ist unter derselben Lizenz lizenziert.
Clusterbasierte Forschung und Entwicklung
Die meisten Avalon-Benutzer tragen in irgendeiner Weise dazu bei. Dadurch wird der Entwicklungs-, Debugging- und Dokumentationsaufwand auf mehrere Benutzer verteilt. Es zeigt auch, dass der Code von Avalon einer umfassenderen Peer-Review unterzogen wurde, als dies bei der Unternehmensentwicklung möglich ist. Darüber hinaus unterstützen Avalon-Benutzer Avalon. Obwohl Open-Source-Projekte normalerweise keinen Helpdesk oder Telefonsupport für heißes Geld haben, haben wir eine Mailingliste. Viele Ihrer Fragen können über die Mailingliste schnell beantwortet werden, schneller als bei manchen Support-Hotlines.
Vereinfachte Analyse und Design
Die Entwicklung auf Basis von Avalon hilft Entwicklern, einen Geisteszustand zu erreichen. In diesem Geisteszustand konzentriert sich die Arbeit des Entwicklers auf die Entdeckung von Komponenten und Diensten. Nachdem nun die Details zur Lebensdauer von Komponenten und Diensten analysiert und entworfen wurden, müssen Entwickler nur noch auswählen, was sie benötigen. Es ist wichtig darauf hinzuweisen, dass Avalon nicht damit begann, die traditionelle objektorientierte Analyse und das traditionelle Design zu ersetzen, sondern es zu verbessern. Sie verwenden immer noch die gleichen Techniken wie zuvor, verfügen aber jetzt über eine Reihe von Tools, mit denen Sie Ihre Entwürfe schneller umsetzen können.

Avalon ist bereit
Avalon Framework, Avalon Excalibur und Avalon LogKit sind für Sie einsatzbereit. Sie sind gereift und werden immer besser. Obwohl Avalon Phoenix und Avalon Cornerstone intensiv weiterentwickelt werden, wird der darauf basierende Code in Zukunft mit nur geringfügigen Änderungen funktionieren.

Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in Avalonjs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn