spring
Dependency Injection (DI) och Inversion of Control (IoC)
Sök…
Anmärkningar
Källkoden för stora programvaror är vanligtvis organiserad i flera enheter. Definitionen av en enhet varierar normalt med det programmeringsspråk som används. Till exempel är kod som är skriven på ett processuellt programmeringsspråk (som C) organiserat i functions
eller procedures
. På liknande sätt organiseras kod i ett objektorienterat programmeringsspråk (som Java, Scala och C #) i classes
, interfaces
och så vidare. Dessa enheter för kodorganisation kan betraktas som enskilda enheter som utgör den övergripande programapplikationen.
När applikationer har flera enheter, växer interberoenden mellan dessa enheter när en enhet måste använda andra för att slutföra sin funktionalitet. De beroende enheterna kan betraktas som consumers
och de enheter som de är beroende av som providers
av specifik funktionalitet.
Den enklaste programmeringsmetoden är för konsumenterna att fullständigt kontrollera flödet av en mjukvaruapplikation genom att bestämma vilka leverantörer som ska instansieras, användas och förstöras vid vilka punkter i det övergripande genomförandet av applikationen. Konsumenterna sägs ha full kontroll över leverantörerna under exekveringsflödet, vilket är dependencies
för konsumenterna. Om leverantörerna har sina egna beroenden kan konsumenterna behöva oroa sig för hur leverantörerna bör initialiseras (och släppas), vilket gör kontrollflödet mer och mer komplicerat när antalet enheter i programvaran ökar. Detta tillvägagångssätt ökar också kopplingen mellan enheter, vilket gör det allt svårare att byta enheter individuellt utan att oroa sig för att bryta andra delar av programvaran.
Inversion of Control (IoC) är en designprincip som förespråkar outsourcing av kontrollflödesaktiviteter som enhetsupptäckt, instansering och förstörelse till en ram som är oberoende av konsumenter och leverantörer. Den bakomliggande principen bakom IoC är att avkoppla konsumenter och leverantörer, frigöra programvarenheter från att behöva oroa sig för att upptäcka, omedelbart och rensa upp sina beroenden och låta enheter fokusera på sin egen funktionalitet. Denna frikoppling hjälper till att hålla mjukvaran utdragbar och underhållbar.
Beroende på injektion är en av teknikerna för att implementera inversionen av kontrollprincipen där instanser av beroenden (leverantörer) injiceras i en mjukvareenhet (konsumenten) istället för att konsumenten måste hitta och instansera dem.
Vårramen innehåller en beroende-injektionsmodul i dess kärna som gör att vårhanterade bönor kan injiceras i andra vårhanterade bönor som beroenden.
Injicera ett beroende manuellt via XML-konfiguration
Tänk på följande Java-klasser:
class Foo {
private Bar bar;
public void foo() {
bar.baz();
}
}
Som framgår måste Foo
klassen anropa metoden baz
en instans av en annan Bar
för att dess metod foo
ska fungera. Bar
sägs vara ett beroende för Foo
eftersom Foo
inte kan fungera korrekt utan en Bar
instans.
Konstruktörsinjektion
När du använder XML-konfiguration för vårram för att definiera vårhanterade bönor, kan en böna av typen Foo
konfigureras enligt följande:
<bean class="Foo">
<constructor-arg>
<bean class="Bar" />
</constructor-arg>
</bean>
eller alternativt (mer verbalt):
<bean id="bar" class="bar" />
<bean class="Foo">
<constructor-arg ref="bar" />
</bean>
I båda fallen skapar vårramen först en instans av Bar
och injects
den till en förekomst av Foo
. Detta exempel antar att klassen Foo
har en konstruktör som kan ta en Bar
instans som en parameter, det vill säga:
class Foo {
private Bar bar;
public Foo(Bar bar) { this.bar = bar; }
}
Den här stilen kallas konstruktionsinjektion eftersom beroendet ( Bar
instans) injiceras genom klasskonstruktören.
Fastighetsinsprutning
Ett annat alternativ att injicera Bar
beroendet i Foo
är:
<bean class="Foo">
<property name="bar">
<bean class="Bar" />
</property>
</bean>
eller alternativt (mer verbalt):
<bean id="bar" class="bar" />
<bean class="Foo">
<property name="bar" ref="bar" />
</bean>
Detta kräver att Foo
klassen har en setter-metod som accepterar en Bar
instans, till exempel:
class Foo {
private Bar bar;
public void setBar(Bar bar) { this.bar = bar; }
}
Injicera ett beroende manuellt via Java-konfiguration
Samma exempel som visas ovan med XML-konfiguration kan skrivas om med Java-konfiguration enligt följande.
Konstruktörsinjektion
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo() { return new Foo(bar()); }
}
Fastighetsinsprutning
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.setBar(bar());
return foo;
}
}
Autowiring ett beroende genom XML-konfiguration
Beroende kan automatiskt anslutas när du använder komponentskanningsfunktionen i vårramen. För att automatisk anslutning ska fungera måste följande XML-konfiguration göras:
<context:annotation-config/>
<context:component-scan base-package="[base package]"/>
där base-package
är det fullt kvalificerade Java-paketet inom vilket våren ska utföra komponentskanning.
Konstruktörsinjektion
Beroende kan injiceras genom klasskonstruktören enligt följande:
@Component
class Bar { ... }
@Component
class Foo {
private Bar bar;
@Autowired
public Foo(Bar bar) { this.bar = bar; }
}
Här är @Autowired
en @Autowired
annotation. Spring stöder också JSR-299 för att möjliggöra applikationsportabilitet till andra Java-baserade injektionsramar för beroende. Detta gör att @Autowired
kan ersättas med @Inject
som:
@Component
class Foo {
private Bar bar;
@Inject
public Foo(Bar bar) { this.bar = bar; }
}
Fastighetsinsprutning
Beroende kan också injiceras med hjälp av settermetoder enligt följande:
@Component
class Foo {
private Bar bar;
@Autowired
public void setBar(Bar bar) { this.bar = bar; }
}
Fältinsprutning
Autowiring tillåter också initialisering av fält inom klassinstanser direkt enligt följande:
@Component
class Foo {
@Autowired
private Bar bar;
}
För vårversion 4.1+ kan du använda Valfritt för valfria beroenden.
@Component
class Foo {
@Autowired
private Optional<Bar> bar;
}
Samma tillvägagångssätt kan användas för konstruktör DI.
@Component
class Foo {
private Optional<Bar> bar;
@Autowired
Foo(Optional<Bar> bar) {
this.bar = bar;
}
}
Autowiring ett beroende genom Java-konfiguration
Constructor injektion genom Java-konfiguration kan också använda autowiring, till exempel:
@Configuration
class AppConfig {
@Bean
public Bar bar() { return new Bar(); }
@Bean
public Foo foo(Bar bar) { return new Foo(bar); }
}