spring
Abhängigkeitsinjektion (DI) und Inversion der Kontrolle (IoC)
Suche…
Bemerkungen
Der Quellcode für große Softwareanwendungen ist normalerweise in mehrere Einheiten organisiert. Die Definition einer Einheit hängt normalerweise von der verwendeten Programmiersprache ab. Beispielsweise ist Code, der in einer prozeduralen Programmiersprache (wie C) geschrieben ist, in functions
oder procedures
. In ähnlicher Weise ist Code in einer objektorientierten Programmiersprache (wie Java, Scala und C #) in classes
, interfaces
usw. organisiert. Diese Einheiten der Codeorganisation können als einzelne Einheiten betrachtet werden, die die gesamte Softwareanwendung bilden.
Wenn Anwendungen über mehrere Einheiten verfügen, treten Abhängigkeiten zwischen diesen Einheiten auf, wenn eine Einheit andere Einheiten verwenden muss, um ihre Funktionalität zu vollenden. Die abhängigen Einheiten können als consumers
und die Einheiten, von denen sie abhängig sind, als providers
bestimmter Funktionen betrachtet werden.
Der einfachste Programmieransatz besteht darin, dass die Verbraucher den Fluss einer Softwareanwendung vollständig steuern, indem sie entscheiden, welche Anbieter an welchen Punkten in der Gesamtausführung der Anwendung instanziiert, verwendet und zerstört werden sollten. Es wird gesagt, dass die Verbraucher während des Ausführungsflusses die volle Kontrolle über die Anbieter haben, die dependencies
für die Verbraucher sind. Falls die Anbieter ihre eigenen Abhängigkeiten haben, müssen sich die Verbraucher möglicherweise Gedanken darüber machen, wie die Anbieter initialisiert (und freigegeben) werden sollten, wodurch der Kontrollfluss mit zunehmender Anzahl der Einheiten in der Software immer komplizierter wird. Dieser Ansatz erhöht auch die Kopplung zwischen den Einheiten, wodurch es zunehmend schwieriger wird, die Einheiten einzeln zu wechseln, ohne sich Gedanken darüber machen zu müssen, dass andere Teile der Software beschädigt werden.
Inversion of Control (IoC) ist ein Design-Prinzip, das die Auslagerung von Kontrollflussaktivitäten wie Einheitenerkennung, Instantiierung und Zerstörung in ein von Verbrauchern und Anbietern unabhängiges Rahmenwerk befürwortet. Das grundlegende Prinzip von IoC besteht darin, Verbraucher und Anbieter zu entkoppeln, um Softwareeinheiten von der Entdeckung, Instantiierung und Beseitigung ihrer Abhängigkeiten zu befreien und es den Einheiten zu ermöglichen, sich auf ihre eigenen Funktionen zu konzentrieren. Diese Entkopplung hilft, die Software erweiterbar und wartbar zu halten.
Abhängigkeitsinjektion ist eine der Techniken zum Implementieren des Umkehrung des Steuerprinzips, wobei Fälle von Abhängigkeiten (Anbieter) in eine Softwareeinheit (den Verbraucher) injiziert werden, anstatt dass der Verbraucher sie finden und instanziieren muss.
Das Spring-Framework enthält im Kern ein Abhängigkeitsinjektionsmodul, mit dem Spring-verwaltete Beans als Abhängigkeiten in andere Spring-verwaltete Beans injiziert werden können.
Injizieren einer Abhängigkeit manuell durch XML-Konfiguration
Betrachten Sie die folgenden Java-Klassen:
class Foo {
private Bar bar;
public void foo() {
bar.baz();
}
}
Wie zu sehen ist, die Klasse Foo
muss die Methode aufzurufen baz
auf eine Instanz einer anderen Klasse Bar
für seine Methode foo
erfolgreich zu arbeiten. Bar
wird als eine Abhängigkeit für Foo
da Foo
ohne eine Bar
Instanz nicht korrekt arbeiten kann.
Konstruktorinjektion
Bei Verwendung der XML-Konfiguration für Spring Framework zur Definition von Spring-verwalteten Beans kann eine Bean vom Typ Foo
wie folgt konfiguriert werden:
<bean class="Foo">
<constructor-arg>
<bean class="Bar" />
</constructor-arg>
</bean>
oder alternativ (ausführlicher):
<bean id="bar" class="bar" />
<bean class="Foo">
<constructor-arg ref="bar" />
</bean>
In beiden Fällen erstellt Spring Framework zunächst eine Instanz von Bar
und injects
sie in eine Instanz von Foo
. In diesem Beispiel wird davon ausgegangen, dass die Klasse Foo
über einen Konstruktor verfügt, der eine Bar
Instanz als Parameter verwenden kann, d. H.
class Foo {
private Bar bar;
public Foo(Bar bar) { this.bar = bar; }
}
Dieser Stil wird als Konstruktorinjektion bezeichnet, da die Abhängigkeit ( Bar
Instanz) über den Klassenkonstruktor eingefügt wird.
Immobilieninjektion
Eine weitere Option zum Einfügen der Bar
Abhängigkeit in Foo
ist:
<bean class="Foo">
<property name="bar">
<bean class="Bar" />
</property>
</bean>
oder alternativ (ausführlicher):
<bean id="bar" class="bar" />
<bean class="Foo">
<property name="bar" ref="bar" />
</bean>
Dazu muss die Foo
Klasse über eine Setter-Methode verfügen, die eine Bar
Instanz akzeptiert, z.
class Foo {
private Bar bar;
public void setBar(Bar bar) { this.bar = bar; }
}
Injizieren einer Abhängigkeit manuell über die Java-Konfiguration
Die gleichen Beispiele wie oben bei der XML-Konfiguration können mit der Java-Konfiguration wie folgt beschrieben werden.
Konstruktorinjektion
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo() { return new Foo(bar()); }
}
Immobilieninjektion
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.setBar(bar());
return foo;
}
}
Automatische Abhängigkeitsabhängigkeit durch XML-Konfiguration
Abhängigkeiten können automatisch verwendet werden, wenn die Komponentensuchfunktion des Spring-Frameworks verwendet wird. Damit die automatische Einstellung funktioniert, muss die folgende XML-Konfiguration vorgenommen werden:
<context:annotation-config/>
<context:component-scan base-package="[base package]"/>
base-package
ist das vollständig qualifizierte Java-Paket, in dem Spring den Komponentenscan durchführen soll.
Konstruktorinjektion
Abhängigkeiten können wie folgt über den Klassenkonstruktor eingefügt werden:
@Component
class Bar { ... }
@Component
class Foo {
private Bar bar;
@Autowired
public Foo(Bar bar) { this.bar = bar; }
}
@Autowired
ist hier eine @Autowired
Anmerkung. Spring unterstützt außerdem JSR-299 , um die Anwendungsportabilität zu anderen Java-basierten Abhängigkeitsinjektionsframeworks zu ermöglichen. Dadurch kann @Autowired
durch @Inject
als:
@Component
class Foo {
private Bar bar;
@Inject
public Foo(Bar bar) { this.bar = bar; }
}
Immobilieninjektion
Abhängigkeiten können auch mit Setter-Methoden wie folgt eingefügt werden:
@Component
class Foo {
private Bar bar;
@Autowired
public void setBar(Bar bar) { this.bar = bar; }
}
Feldinjektion
Die automatische Einstellung ermöglicht das direkte Initialisieren von Feldern in Klasseninstanzen wie folgt:
@Component
class Foo {
@Autowired
private Bar bar;
}
Für Spring-Versionen 4.1 und höher können Sie optional für optionale Abhängigkeiten verwenden.
@Component
class Foo {
@Autowired
private Optional<Bar> bar;
}
Der gleiche Ansatz kann für Konstruktor DI verwendet werden.
@Component
class Foo {
private Optional<Bar> bar;
@Autowired
Foo(Optional<Bar> bar) {
this.bar = bar;
}
}
Automatische Abhängigkeit einer Abhängigkeit durch Java-Konfiguration
Constructor-Injection durch Java-Konfiguration kann auch automatische Einstellungen verwenden, z.
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo(Bar bar) { return new Foo(bar); }
}