Spring este un framework redus ca dimensiuni, dar în acelaşi timp flexibil şi universal, orientat spre a facilita crearea de aplicații Java SE şi Java EE. Este un framework “open source” creat de Rod Johnson în 2003, având ca țintă simplificarea modului de dezvoltarea a aplicațiilor J2EE.
Spring Framework urmăreşte să ofere infrastructura necesară pentru realizarea aplicațiilor Java, astfel încât programatorul să se poată concentra asupra dezvoltării efective de cod. Spring utilizează pe scară largă obiecte Java clasice (POJOs – Plain Old Java Objects).
Dependențele între obiecte
La bază, o aplicație Java constă din obiecte care colaborează între ele pentru soluționarea unei probleme – obiectele dintr-o aplicație având dependențe între ele.
Platforma Java nu dispune de mijloacele necesare pentru a organiza obiectele, această sarcină revenind dezvoltatorilor şi arhitecților care au la dispoziție pattern-urile clasice (design patterns) pentru a organiza clasele şi obiectele. Totuşi, acestea trebuie implementate de către programator.
Facilitatea de inversiune a controlului (Inversion of Control – IoC) pusă la dispoziție de Spring Framework adresează această problemă – organizarea obiectelor – oferind mijloacele necesare pentru a permite componentelor disparate să fie asamblate într-o aplicație funcțională.
Vom porni de la un exemplu, care va ilustra cum pot fi gestionate dependențele între obiecte. Exemplul ilustrează o situație simplă, în care avem la dispoziție două clase, una dintre acestea ținând o referință către un obiect aparținând celei de-a doua clase. Dorim să punem în evidență modalitățile de a menține această dependență.
Abordarea tradițională menține legătura dintre clase în interiorul codului.
public class Person { private String name; private Company company;
public Person() { name = "John Smith"; company = new Company(); company.setName("ABC Software"); } }
public class Company { private String name;
public void setName(String name) { this.name = name; } }
Codul de mai sus creează un obiect aparținând clasei Company pe care îl utilizează într-un singur loc – o abordare ineficientă. Astfel, abordarea tradițională poate fi rezumată în schema de mai jos, care surprinde mai general modul cum sunt tratate dependențele între obiecte.
Problemele care pot fi constatate în această abordare sunt:
- Clasa A depinde în mod direct de clasa B. Clasele sunt strâns cuplate, eventualele schimbări propagându-se în cod.
- Este imposibil să testăm clasa A separat de clasa B, menținând acelaşi cuplaj.
- Ciclul de viață al obiectului de tip B depinde de obiectul de tip A – este imposibil să utilizăm obiectul de tip B în alte locuri.
- Nu este posibil să înlocuim clasa B cu o altă implementare. Ori, în dinamica proiectului, acest lucru se poate întâmpla in mod frecvent.
Abordarea Spring asupra dependențelor între obiecte
Injectarea dependenței (Dependency Injection – DI) este cunoscută şi drept inversiune de control (Inversion of Control – IoC).
Este un proces prin care obiectele îşi definesc dependențele – mai exact, alte obiecte către care păstrează referințe – cu ajutorul argumentelor de constructori, argumentelor de metode “factory” sau proprietăților care sunt setate de către obiect după ce acesta a fost construit.
Injectarea acestor dependențe este realizată de containerul care se ocupă de gestiunea bean-urilor.
Acest proces este în mod fundamental inversul celui tradițional, de aici şi denumirea de inversiune de control (Inversion of Control – IoC), bean-ul fiind cel care îşi controlează instanțierea şi localizarea dependențelor.
public class Person { private String name; private Company company; }
public class Company { private String name; }
Dependențele sunt menținute separate, într-un fişier de configurare XML.
<bean id=”smith” class=”Person”>
<property name=”name” value=”John Smith”/>
<property name=”company” ref=”luxoftCompany”/>
</bean>
<bean id=”luxoftCompany” class=”Company”>
<property name=”name” value=”Luxoft”/>
</bean>
Avantajele acestui tip de abordare:
- Atunci când este solicitat un obiect, containerul este cel care decide ce anume trebuie returnat.
- Pentru oricare din tipuri, dependențele sunt înregistrate la nivelul containerului.
- Clasele Person şi Company nu sunt dependente între ele şi nu sunt dependente de alte biblioteci externe.
- Fişierul de configurare XML documentează configurarea sistemului şi dependențele între obiecte.
- Containerul este cel care controlează ciclul de viață al obiectelor create.
- Este facil să se realizeze schimbări asupra dependențelor obiectelor din sistem.
Astfel, evoluția care porneşte de la abordarea tradițională este următoarea:
Inițial, dependințele erau ținute în interiorul codului:
Abordarea bazată pe JNDI (Java Naming And Directory Interface) permite obiectelor să acceseze dependințele pe care trebuie să le construiască.
În fine, abordarea Spring, bazată pe inversiunea controlului, permite unui obiect să nu cunoască nimic despre alte obiecte. Injectarea dependințelor revine în sarcina containerului.
Concluzii
- Inversiunea de control (IoC) este baza framework-ului Spring şi mai este cunoscută şi sub denumirea de “Principiul Hollywood”: “Nu ne căutați dumneavoastră, vă vom căuta noi”.
- Ideea de bază este de a elimina dependența componentelor aplicației de anumite implementări şi de a delega către container drepturile de a controla instanțierea claselor.
- Martin Fowler a sugerat numele de injectare a dependenței (Dependency Injection – DI), considerând că reflectă mai bine esența acestui pattern.
Avantajele containerelor IoC:
- Se poate realiza managementul dependințelor şi modificarea acestora fără a fi nevoie de recompilarea codului. Astfel, timpul de dezvoltare şi numărul de operații de efectuat de programatori se reduce.
- Facilitează reutilizarea claselor, aspect esențial în programarea orientată pe obiecte.
- Simplifică procesul de testare unitară, reducând de asemenea timpul de dezvoltare.
- Codul poate fi menținut mai simplu, nu este nevoie de inițializarea unor obiecte auxiliare – complexitatea sistemului scade.
- Este recomandat în mod special să se insereze în interiorul containerului acele obiecte a căror implementare se poate schimba.
Post-ul Inversiunea de control prin Spring Framework apare prima dată în Ctrl-D.