Dependency Injection Container für JavaScript (Node.js): Awilix
\n\nIn der modernen Entwicklung mit Node.js ist die Aufrechterhaltung einer sauberen Architektur und der Testbarkeit von Code von entscheidender Bedeutung. Eines der wichtigsten Muster, die dabei helfen, ist Dependency Injection (DI) – die Abhängigkeitsinjektion. Für die effiziente Umsetzung dieses Musters in der JavaScript-Umgebung wurden spezialisierte Bibliotheken entwickelt – Dependency Injection Container. In diesem Artikel betrachten wir eine der beliebtesten und leichtgewichtigsten Bibliotheken im Detail: Awilix.
\n\nWas ist Dependency Injection und wozu braucht man einen Container?
\n\nIm traditionellen Ansatz erstellt ein Objekt seine Abhängigkeiten selbst (z. B. mit dem new-Operator). Dies führt zu einer starken Kopplung des Codes, was das Testen und die Änderung erschwert. Das Dependency Injection-Muster schlägt vor, Abhängigkeiten von außen zu übergeben (zu injizieren). Der Container automatisiert diesen Prozess: Er weiß, wie Objekte und ihre Abhängigkeiten erstellt werden, und stellt auf Anfrage fertige Instanzen bereit.
Awilix: Ein leichter und leistungsstarker DI-Container
\n\nAwilix ist eine Bibliothek für JavaScript (Node.js), die das Inversion of Control (IoC)-Muster mithilfe eines Containers implementiert. Sie wurde von Grund auf für Node.js geschrieben, unterstützt die asynchrone Auflösung von Abhängigkeiten, verschiedene Registrierungsstile (Klassen, Fabriken, Werte) und die automatische Erkennung von Abhängigkeiten über den Konstruktor.
\n\nHauptfunktionen:
\n- \n
- Automatische Injektion: Der Container analysiert die Parameter des Konstruktors oder der Funktion und injiziert automatisch die benötigten Abhängigkeiten. \n
- Asynchronitätsunterstützung: Abhängigkeiten können asynchron sein (z. B. eine Datenbankverbindung), und der Container wartet korrekt auf deren Auflösung. \n
- Verschiedene Registrierungsmodi: Sie können Klassen (
asClass), Factory-Funktionen (asFunction) oder fertige Werte (asValue) registrieren. \n - Scopes (Gültigkeitsbereiche): Es werden verschiedene Lebenszyklen von Objekten unterstützt (Singleton, Transient, Scoped). \n
- Modularität: Der Container kann einfach in Module aufgeteilt werden, und Abhängigkeiten können in verschiedenen Teilen der Anwendung registriert werden. \n
Installation und grundlegende Verwendung
\n\nDie Installation von Awilix erfolgt über npm:
\n\nnpm install awilix\n\nBetrachten wir ein einfaches Beispiel. Angenommen, wir haben einen Dienst für die Benutzerverwaltung, der von einem Logger und einem Repository abhängt.
\n\nconst { createContainer, asClass, asFunction, asValue } = require('awilix');\n\n// 1. Abhängigkeiten definieren\nclass Logger {\n log(message) {\n console.log(`[LOG]: ${message}`);\n }\n}\n\nclass UserRepository {\n constructor({ logger }) {\n this.logger = logger;\n }\n\n findById(id) {\n this.logger.log(`Suche nach Benutzer mit ID: ${id}`);\n return { id, name: 'John Doe' };\n }\n}\n\nclass UserService {\n constructor({ userRepository, logger }) {\n this.userRepository = userRepository;\n this.logger = logger;\n }\n\n getUser(id) {\n this.logger.log('Anfrage an UserService');\n return this.userRepository.findById(id);\n }\n}\n\n// 2. Container erstellen und Abhängigkeiten registrieren\nconst container = createContainer();\n\ncontainer.register({\n logger: asClass(Logger).singleton(),\n userRepository: asClass(UserRepository).singleton(),\n userService: asClass(UserService).singleton()\n});\n\n// 3. Container verwenden, um den Dienst zu erhalten\nconst userService = container.resolve('userService');\nconst user = userService.getUser(1);\nconsole.log(user);\n// Ausgabe:\n// [LOG]: Anfrage an UserService\n// [LOG]: Suche nach Benutzer mit ID: 1\n// { id: 1, name: 'John Doe' } Auch in der Bibliothek
Generierung von PDF-Berichten in PHP: Überblick über Bibliotheken und Beispiele
Rate Limiting in Rust: Bibliotheken zur Begrenzung der Anfragefrequenz
Lodash für JavaScript (Node.js): Vollständiger Leitfaden mit Beispielen