spring
Wstrzykiwanie zależności (DI) i inwersja kontroli (IoC)
Szukaj…
Uwagi
Kod źródłowy dla dużych aplikacji jest zazwyczaj podzielony na wiele jednostek. Definicja jednostki zwykle różni się w zależności od używanego języka programowania. Na przykład kod napisany w proceduralnym języku programowania (takim jak C) jest zorganizowany w functions
lub procedures
. Podobnie, kod w obiektowym języku programowania (takim jak Java, Scala i C #) jest zorganizowany w classes
, interfaces
i tak dalej. Te jednostki organizacji kodu można traktować jako pojedyncze jednostki tworzące całą aplikację.
Gdy aplikacje mają wiele jednostek, wzajemne zależności między tymi jednostkami pojawiają się, gdy jedna jednostka musi użyć innych, aby zakończyć swoją funkcjonalność. Jednostki zależne można traktować jako consumers
a jednostki, od których są zależne, jako providers
określonych funkcji.
Najłatwiejszym podejściem do programowania jest to, aby konsumenci mieli pełną kontrolę nad przepływem aplikacji, decydując, którzy dostawcy powinni zostać utworzeni, utworzeni i zniszczeni w jakich momentach ogólnej realizacji aplikacji. Mówi się, że konsumenci mają pełną kontrolę nad dostawcami podczas procesu wykonywania, które są dependencies
dla konsumentów. W przypadku, gdy dostawcy mają swoje własne zależności, konsumenci mogą się martwić o to, w jaki sposób dostawcy powinni zostać zainicjowani (i zwolnieni), co czyni przepływ kontroli coraz bardziej skomplikowanym w miarę wzrostu liczby jednostek w oprogramowaniu. Takie podejście zwiększa również sprzężenie między jednostkami, co sprawia, że coraz trudniej jest zmieniać jednostki indywidualnie, nie martwiąc się o uszkodzenie innych części oprogramowania.
Inwersja kontroli (IoC) to zasada projektowania, która zaleca outsourcing działań związanych z kontrolą przepływu, takich jak wykrywanie jednostek, tworzenie instancji i niszczenie, w ramach niezależnych od konsumentów i dostawców. Podstawową zasadą stojącą za IoC jest oddzielenie konsumentów i dostawców, uwalniając jednostki oprogramowania od konieczności martwienia się o odkrywanie, tworzenie instancji i czyszczenie ich zależności oraz umożliwianie jednostkom skupienia się na własnej funkcjonalności. To oddzielenie pomaga utrzymać rozszerzalność i łatwość utrzymania oprogramowania.
Wstrzykiwanie zależności jest jedną z technik wdrażania zasady inwersji kontroli, w której przypadki zależności (dostawcy) są wstrzykiwane do jednostki oprogramowania (konsumenta) zamiast konieczności ich znajdowania i tworzenia przez użytkownika.
Struktura Spring zawiera moduł wstrzykiwania zależności w swoim rdzeniu, który umożliwia wstrzykiwanie fasoli zarządzanych przez Spring do innych fasoli zarządzanych przez Spring jako zależności.
Ręczne wstrzykiwanie zależności za pomocą konfiguracji XML
Rozważ następujące klasy Java:
class Foo {
private Bar bar;
public void foo() {
bar.baz();
}
}
Jak można zobaczyć, klasa Foo
musi wywołać metodę baz
na instancji innej klasy Bar
aby jej metoda foo
działała pomyślnie. Mówi się, że Bar
jest zależnością dla Foo
ponieważ Foo
nie może działać poprawnie bez instancji Bar
.
Wtrysk konstruktora
Podczas korzystania z konfiguracji XML dla środowiska Spring do definiowania komponentów bean zarządzanych przez Spring, komponent bean typu Foo
można skonfigurować w następujący sposób:
<bean class="Foo">
<constructor-arg>
<bean class="Bar" />
</constructor-arg>
</bean>
lub, alternatywnie (bardziej szczegółowe):
<bean id="bar" class="bar" />
<bean class="Foo">
<constructor-arg ref="bar" />
</bean>
W obu przypadkach framework Spring najpierw tworzy instancję Bar
i injects
ją do instancji Foo
. W tym przykładzie założono, że klasa Foo
ma konstruktor, który może przyjąć instancję Bar
jako parametr, to znaczy:
class Foo {
private Bar bar;
public Foo(Bar bar) { this.bar = bar; }
}
Ten styl jest nazywany wstrzykiwaniem konstruktora, ponieważ do konstruktora klasy wstrzykuje się zależność (instancja Bar
).
Zastrzyk nieruchomości
Inną opcją wstrzyknięcia zależności Bar
do Foo
jest:
<bean class="Foo">
<property name="bar">
<bean class="Bar" />
</property>
</bean>
lub, alternatywnie (bardziej szczegółowe):
<bean id="bar" class="bar" />
<bean class="Foo">
<property name="bar" ref="bar" />
</bean>
Wymaga to, aby klasa Foo
miała metodę ustawiającą, która akceptuje instancję Bar
, na przykład:
class Foo {
private Bar bar;
public void setBar(Bar bar) { this.bar = bar; }
}
Ręczne wstrzykiwanie zależności za pomocą konfiguracji Java
Te same przykłady, jak pokazano powyżej w konfiguracji XML, można ponownie zapisać w konfiguracji Java w następujący sposób.
Wtrysk konstruktora
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo() { return new Foo(bar()); }
}
Zastrzyk nieruchomości
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.setBar(bar());
return foo;
}
}
Automatyczne oparcie zależności poprzez konfigurację XML
Zależności można automatycznie rejestrować podczas korzystania z funkcji skanowania komponentów środowiska Spring. Aby automatyczne wiązanie działało, należy wykonać następującą konfigurację XML:
<context:annotation-config/>
<context:component-scan base-package="[base package]"/>
gdzie base-package
to w pełni kwalifikowany pakiet Java, w ramach którego Spring powinien wykonać skanowanie komponentów.
Wtrysk konstruktora
Zależności można wstrzykiwać za pomocą konstruktora klasy w następujący sposób:
@Component
class Bar { ... }
@Component
class Foo {
private Bar bar;
@Autowired
public Foo(Bar bar) { this.bar = bar; }
}
Tutaj @Autowired
jest adnotacją dotyczącą wiosny. Spring obsługuje również JSR-299, aby umożliwić przenoszenie aplikacji do innych platform wstrzykiwania zależności opartych na Javie. Dzięki temu @Autowired
można zastąpić @Inject
jako:
@Component
class Foo {
private Bar bar;
@Inject
public Foo(Bar bar) { this.bar = bar; }
}
Zastrzyk nieruchomości
Zależności można również wstrzykiwać za pomocą metod ustawiających w następujący sposób:
@Component
class Foo {
private Bar bar;
@Autowired
public void setBar(Bar bar) { this.bar = bar; }
}
Iniekcja polowa
Automatyczne okablowanie pozwala również na bezpośrednie inicjowanie pól w instancjach klas w następujący sposób:
@Component
class Foo {
@Autowired
private Bar bar;
}
W wersjach wiosennych 4.1+ możesz użyć Opcjonalnej dla opcjonalnych zależności.
@Component
class Foo {
@Autowired
private Optional<Bar> bar;
}
To samo podejście można zastosować do konstruktora DI.
@Component
class Foo {
private Optional<Bar> bar;
@Autowired
Foo(Optional<Bar> bar) {
this.bar = bar;
}
}
Automatyczne oparcie zależności poprzez konfigurację Java
Wstrzykiwanie konstruktora przez konfigurację Java może również wykorzystywać automatyczne okablowanie, takie jak:
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo(Bar bar) { return new Foo(bar); }
}