You are on page 1of 10

Tartu Ülikool

Matemaatika-informaatika teaduskond
Arvutiteaduse instituut

IoC konteineri tööpõhimõte:


Spring Framework, PicoContainer

Referaat

Koostaja: Rein Raudjärv


Juhendaja: Ivo Mägi

Tartu 2005
Sisukord
Sissejuhatus ................................................................................................................................ 3
1. Spring Framework.................................................................................................................. 4
1.1. Beanide konfigureerimine ............................................................................................... 4
1.2. Beanide sidumine ............................................................................................................ 5
2. PicoContainer ......................................................................................................................... 7
2.1. Komponentide konfigureerimine ja sidumine................................................................. 7
Kokkuvõte .................................................................................................................................. 9
Kasutatud kirjandus.................................................................................................................. 10

2
Sissejuhatus
Objekt-orienteeritud programmeerimises nimetatakse konteineriks (container) antud prog-
rammeerimiskeele objektide dünaamilist hoidlat, kuhu saab uusi objekte lisada ja vanu
eemaldada kogu programmi tööaja (run-time) vältel.

Harilikult muretseb iga programmeerimiskeele objekt ise selle eest, et tal oleksid olemas kõik
vajalikud objektid, millega suhelda. Ta kas loob oma seosed ise või saab need mingi teise
objekti käest. Vastupidist printsiipi, kus objektid ise ei halda oma sõltuvusi, nimetatakse
kontrolli ümberpööramiseks (Inversion of Control – IoC).

IoC printsiip ei määra kuidas ning mille alusel objektid endale sõltuvused saavad. Seda täp-
sustab nn sõltuvuste sisestuse printsiip (Dependency Injection – DI), kus iga objekti puhul
kontrollitakse, mida tal oma tööks vaja läheb, ning sisestatakse talle vajalikud sõltuvused.
Seda kutsutakse ka nn. Hollywoodi printsiibiks „Ära helista meile, me helistame sulle“
(„Don't call us, we'll call you“). Sõltuvusi võib lahendada nii tüübi, nime kui mõne muu kri-
teeriumi alusel. Objektide hoidlat, mis seda protsessi juhib, nimetatakse IoC konteineriks.

Sageli peetakse IoC ja DI printsiipe ekslikult sünonüümideks. Lisaks DI printsiibile vastab


IoC printsiibile ka teenuse lokaatori (Service Locator) printsiip, kus iga objekt küsib endale
seosed mingi kolmanda, harilikult staatilise, objekti käest.

IoC on hetkel kõige populaarsem Java maailmas. Objekti sõltuvuste all mõeldakse siin vii-
teid, mida üks objekt omab teistele objektidele. Vastavalt sellele, kas seosed määratakse ob-
jekti loomisel konstruktori argumentidena või pärast seda set-meetodite esile kutsumisega
eristatakse Constructor Injection ning Setter Injection printsiipe. Lisaks kasutakse vahel ka nn
liideste kaudu seoste sisestamist (Interface Injection).

Lisaks sõltuvustele, võib IoC konteiner sisestada objektidele ka muid muutujate väärtusi. Ob-
jekti andmete üldist seadistamist nimetatakse tema konfiguratsiooniks.

Käesolevas referaadis vaatleme põgusalt kahte Java keele IoC konteinerit: Springi raamis-
tikku (Spring Framework) ning PicoContainerit. Esimese puhul püüame ka rõhutada, mis
kasu IoC printsiibist üldisemalt on.

3
1. Spring Framework
Springi eesmärk on teha ärirakenduste arendamise lihtsamaks. Võrreldes millega? Võrreldes
eelkõige keerulise kohmaka ja aeglase EJB tehnoloogiaga. Aga mitte ainult...

Spring loodi vastamaks järgmistele tõekspidamistele:

• Hea disain on tähtsam kui alustehnoloogia.


• JavaBeanide vabalt ühendamine läbi liideste on hea mudel.
• Koodi peaks olema kerge testida.

Seega ei piirdu Springi võimalused ainult serveripoolsete rakenduste arendamisega.

Spring on kerge ümberpööratud kontrolli (IoC) ja aspekt-orienteeritud (Aspect Oriented –


AOP) konteiner-raamistik. Springi JAR faili maht on natuke üle 1MB.

Springi konteiner sisaldab ja haldab kõigi rakenduse objektide e. beanide elutsüklit ning kon-
figuratsiooni. Tema raamistik võimaldab konfigureerida ja luua keerukat rakendust lihtsama-
test komponentidest. Springis luuakse rakenduse objektid deklaratiivselt, harilikult XML-is.

Springil on oma MVC (Model-View-Controller) raamistik, mida võib kasutada nii JSP-ga kui
integreerida mõne muu raamistikuga. Lisaks hõlbustab Spring transaktsioonide ja andmesal-
vestuse raamistike integreerimist jms, jättes arendaja kirjutada eelkõige äriloogika.

1.1. Beanide konfigureerimine

Springi raamistiku objektid e. beanid konfigureeritakse ära reeglina XML failis.

Bean võib olla suvaline Java objekt. Ta ei pea vastama mingile liidesele ega omama mingit
kindlat konstruktorit vms. Tema loomine võib toimuda ka läbi teise klassi staatilise meetodi.

Oletame, et meil on olemas klass nimega „MinuKlass“:

package minuPakett;
public class MinuKlass {
private String minuMuutuja;
public void setMinuMuutuja(String minuMuutuja) {
this.minuMuutuja = minuMuutuja;
}
}
Triviaalne Springi konfiguratsiooni XML fail (nt. beans.xml) näeb välja järgmine:

<beans>
<bean id="minuBean" class="minuPakett.MinuKlass">
<property name="minuMuutuja" value="minuVaartus" />
</bean>
</beans>

4
Iga Springi seadete XML faili juurmärgis (root tag) on <beans>. Antud fail kirjeldab ära ühe
paketi minuPakett klassi MinuKlass beani, mille objekt luuakse konstruktoriga MinuKlass()
ning millele antakse unikaalne tunnus minuBean. Seejärel kutsutakse antud objektil esile mee-
tod setMinuMuutuja(“minuVaartus“).

Igal beanil on tema unikaalne tunnus e. Id. Kui kõik beanid on erinevate klasside objektid, st.
ühestki klassist ei looda mitut beani, siis kasutatakse teatud juhtudel ka Java klasse beanide
identifitseerimiseks, kuid see võib tekitada vahel probleeme.

Objekti konfigureerimist set-meetoditega nimetakse ka Setter Injection printsiibiks. Lisaks


võimaldab Spring konfigureerida objekte ka konstruktori argumentide konfigureerimisega
(Constructor Injection), kuid raamistiku autorid eelistavad rohkem set-meetodite kasutamist.
Muutuja väärtused, mis konfiguratsioonis määratakse, võivad olla nii primitiivid kui lihtsa-
mad objektid, massiivid või Collectionid. Lisaks saab ise defineerida uusi teisendajad, mis
sõnest mingi klassi isendi loovad.

Vaikimisi luuakse igast beanist ainult üks isend e. Singleton. Samas on võimalik bean defi-
neerida ka prototüübina (Prototype), mille põhjal luuakse antud klassi uus isend iga kord kui
selle beani poole pöördutakse. Seepärast ei lange beani ja Java objekti mõiste päris üks-
üheselt kokku. Igale beanile saab määrata ka init ja destroy meetodi, mis vastavalt pärast tema
isendi loomist ning enne kustutamist (Garbage Collection) esile kutsutakse.

1.2. Beanide sidumine

Oletame, et meil on ka teine klass „MinuTeineKlass“:

package minuPakett;
public class MinuTeineKlass {
private MinuKlass minuBean;
public void setMinuBean(MinuKlass minuBean) {
this.minuBean = minuBean;
}
}
Selle konfigureerimiseks täiendame beans.xml faili, kuhu lisame juurde:

<bean id="minuTeineBean" class="minuPakett.MinuTeineKlass">


<property name="minuBean" ref="minuBean" />
</bean>
Antud kirjeldus tähendab, et pärast beani minuTeineBean loomist antakse talle set-meetodi
kaudu minuBean isend.

Niiviisi luuaksegi XML failis objektide vahelisi seoseid. Mis sellest kasu on? Kasu on selles,
et antud juhul võime panna klassi minuKlass realiseerima mingit liidest ning klassi

5
minuTeineKlass panna sõltuma sellest liidesest, mitte realisatsioonist. Kui minuTeineKlass
looks ise endale minuKlass() konstruktoriga uue isendi, siis peaks ta juba teadma selle klassi
nime. Springi eesmärk on siduda objekte liideste abil, sest siis saab rakenduse komponente
paremini välja vahetada, näiteks testimisel kasutada libarealisatsioone (Mock objects). Samas
võib siis alati asendada klassi tema mingi alamklassiga, mis täpsustab realisatsiooni.

Lisaks nime teadmisele peaks minuTeineKlass teadma ka kuidas klassi minuKlass isendit
konfigureerida. Sama kehtib iga klassi kohta, mis klassi minuKlass isendit vajab. See tähen-
dab aga, et objektide konfiguratsiooni ei saa kergesti muuta, sest see asub paljudes kohtades.
Springi eesmärk on hoida objektide konfiguratsioon ja nende realisatsioon lahus. See
võimaldab näiteks testimise korral asendada kergesti DataSource’i asukohta vms.

Lisaks käsitsi objektide sidumisele, saab kasutada ka auto-wiring metoodikat, mis püüab luua
automaatselt kõik beanide omavahelised seosed, võrreldes omavahel beanide klasse ning set-
meetodi argumendi klasse. Automaatset sidumist ei saa kasutada, kui sama klassi põhjal defi-
neeritakse rohkem beane.

Järgneva koodiga luuakse antud konfiguratsiooniga Springi konteineri isend ning omistatakse
lokaalmuutujale konteineri poolt loodud minuTeineBean isend:

XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beans.xml",


getClass()));
MinuTeineKlass minuTeineBean = (MinuTeineKlass)
bf.getBean("minuTeineBean");
Veebirakenduste puhul lisatakse web.xml faili vastav Springi Servlet, mis suunab päringud
MVC raamistikule. Viimane konfigureeritakse samuti reeglina XML failis.

Komponendi küsimine otse konteineri käest on risti vastupidine IoC põhimõttele, mille ko-
haselt tuleb kõik komponentide vahelised seosed määrata konteineri konfiguratsioonis.
Erandiks on rakenduse käivitamine jms.

6
2. PicoContainer
PicoContainer on kerge ja sissejuhatav IoC konteiner, mille JAR faili maht on umbes 100KB.

Pico on kirjutatud algselt Javas, kuid nüüdseks on ta levinud ka .NET, Ruby ning PHP plat-
vormile.

PicoContaineri konfigureerimine toimub Java koodis (teiste platvormide korral nende keeles).
XML jms formaatide kasutamiseks on ehitatud Pico peale eraldi NanoContainer.

2.1. Komponentide konfigureerimine ja sidumine

PicoContaineri rakenduse objekte nimetatakse komponentideks (Components). Komponendid


ei pea realiseerima mingit kindlat liidest.

Jätkame siinkohal Springi näitega, mille kohendame Pico konteineri jaoks pisut ümber:

package minuPakett;
public class MinuKlass {
private String minuMuutuja;
public MinuKlass(String minuMuutuja) {
this.minuMuutuja = minuMuutuja;
}
}

package minuPakett;
public class MinuTeineKlass {
private MinuKlass minuBean;
public MinuTeineKlass(MinuKlass minuBean) {
this.minuBean = minuBean;
}
}
Nagu näha, kasutame siinkohal set-meetodite asemel konstruktoreid. PicoContainer võimal-
dab kasutada ka Setter Injection printsiipi, kuid on mõeldud eelkõige konstruktorite abil ob-
jektide konfigureerimiseks. Viimast põhjendatakse väitega, et niiviisi saab paremini kontrolli-
da, et igast klassist loodaks ainult valiidseid isendeid. Vastupidine välistatakse vastava konst-
ruktori puudumisega. Samas muutub konstruktorite kasutamine keeruliseks, kui konstrukto-
reid tekib palju ning nende argumendid on sama tüüpi. Sel juhul on kindlam kasutada set-
meetodeid.

Springi näite kohase konfiguratsiooniga konteineri loomine käib Pico puhul järgmiselt:

MutablePicoContainer pico = new DefaultPicoContainer();


Parameter[] params = {new ConstantParameter("minuVaartus")};
pico.registerComponentImplementation("minuBean", MinuKlass.class, params);
pico.registerComponentImplementation(MinuTeineKlass.class);

7
Klassi MinuKlass komponendist isendi loomiseks määrame ette konstruktori parameetrid, ühe
sõne „MinuVaartus“. Komponendile antakse ka unikaalne tunnus „minuBean“. Klassi
MinuTeineKlass komponendi loomine on näites pisut abstraktsem, sest tema konstruktori pa-
rameetrid määrab PicoContainer ise analoogselt Springi auto-wiring viisile. Kuna antud klas-
sil on ainult üks konstruktor ning see nõuab klassi isendit, mis on juba konteineris olemas, siis
antaksegi talle see.

Pico puhul eelistatakse, et igast klassist luuakse ainult üks komponent. Seepärast jäetakse
komponentide Id-d harilikult määramata ning konteinerist võetakse komponente klassi järgi.

Komponendi MinuTeineKlass isendi saame konteinerist järgmiselt:

MinuTeineKlass minuTeineBean = (MinuTeineKlass)


pico.getComponentInstance(MinuTeineKlass.class);
Komponendi küsimine otse konteineri käest on risti vastupidine IoC põhimõttele, mille ko-
haselt tuleb kõik komponentide vahelised seosed määrata konteineri konfiguratsioonis.
Erandiks on rakenduse käivitamine jms.

8
Kokkuvõte
Kontrolli ümberpööramise e. Inversion of Control printsiip muudab tarkvara arenduse objekt-
orienteeritud programmerimise maailmas oluliselt lihtsamaks. Liideste abil objektide sidumi-
ne võimaldab palju kergemini rakenduse komponente vahetada ning neid testida. Lisaks on
kood ka kergemini loetavam, sest keerulisi objektide „otsimisi“ asendavad lihtsad konstrukto-
rid või set-meetodid.

Spring Framework, PicoContainer jt IoC konteinerid on arenenud kiiresti.

PicoContainer on mõeldud eelkõige IoC tööpõhimõttega tutvujatele. Ta on väga väike ning ei


paku mingeid lisavõimalusi. Samas ei sõltu ta ka teistest komponentidest. Picot saab lisaks
Javale kasutada ka .NET, Ruby ning PHP keele puhul.

Spring, mis on nii IoC kui AOP raamistik ja asendab funktsionaalselt ka EJB võimalusi, on
tõestanud, et ka lihtsa disainiga võib toota keerukaid ärirakendusi. Hoolimata paljudest või-
malustest, on Springi raamistik väga modulaarne st. korraga võib kasutada temast suvalist
alamhulka. Lisaks sõltuvad Springis tehtud rakendused oma raamistikust minimaalselt.

Mõlemad konteinerid toetavad nii Constructor kui Setter Injection printsiipi, kuid
PicoContainerit on soovitav kasutada eelkõige ainult esimesel juhul ning Springi teisel. Kon-
teinerite objektid ei pea sealjuures laiendama ühtegi klassi ega realiseerima mingit liidest.

9
Kasutatud kirjandus
• Craig Walls, Ryan Breidenbach, „Spring in Action“
• Introduction to the Spring Framework,
http://www.theserverside.com/articles/article.tss?l=SpringFramework
• Inversion of Control Containers and the Dependency Injection pattern,
http://www.martinfowler.com/articles/injection.html
• PicoContainer, http://www.picocontainer.org/
• Spring Framework, http://www.springframework.org/
• Wikipedia, http://en.wikipedia.org/

10

You might also like