Java User Group Marche
http://www.jugancona.org – [email protected]
Spring tutorial: Spring core
di Andrea Del Bene
Introduzione.
In questa parte del tutorial inizieremo a “sporcarci” le mani con un pò di codice
basato su spring. Vedremo in particolare come sono strutturati i file xml usati da
spring per configurare il contesto. Va detto subito che l'xml non è l'unico modo per
configurare dei bean all'interno di un contesto Spring, ma è sicuramente la tecnica
più utilizzata e meno invasiva. Metodi alternativi esistono solo da qualche mese e
sarebbe prematuro introdurli ora.
Dizionario e richiami.
Per familiarizzare con Spring occorre avere chiari alcuni concetti chiave della
programmazione orientata agli oggetti. Di seguito richiameremo quei pochi che ci
occorrono per continuare la lettura del tutorial.
•
Classe: la classe è un'entità che modella un concetto reale trattato dalla
nostra applicazione.
Es:una persona, un ordine acquisto, un conto corrente, ecc...
La classe rappresenta un sottoinsieme delle caratteristiche del concetto reale
corrispondente, in modo da fornire un modello semplice ed affidabile allo
stesso tempo.
Es: se si vuole creare una classe Persona da usare in un'anagrafica clienti
difficilmente si terrà traccia del loro numero di scarpe, a meno che il
programma non gestisca un negozio di calzature :).
In Java la classe corrisponde proprio al costrutto class che usiamo per definire
le classi del nostro dominio.
•
Attributi: gli attributi sono le caratteristiche proprie di una classe, ossia le
informazioni che abbiamo deciso di modellare nella nostra classe rispetto il suo
corrispettivo reale.
Es: se di una persona mi interessano nome, cognome e data di nascita, la mia
classe persona avrò proprio tre attributi nome, cognome, dataDiNascita (nei
nomi attributi non ci sono spazi ovviamente).
•
Metodi: sono funzioni interne alla classe che possono operare sugli attributi
della classe o su altri dati forniti dall'esterno. I metodi rappresentano anche le
operazioni che la classe espone all'esterno e si parla in questo caso di metodi
public(pubblici). Per avvicinarsi a Spring è necessario sapere cosa sono i
metodi getter e setter di una classe. I primi restituiscono il valore di un
attributo di una classe, i secondi impostano il valore di una un attributo.
Es: per ottenere e impostare il nome di una Persona la classe esporrà i metodi
getNome() e setNome(String nome) entrambi pubblici. Per convenzione i
getter e setter hanno come nome rispettivamente get<NomeCampo> e
<setNomeCampo>.
Andrea Del Bene – Spring core
1 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
•
Istanza: l'istanza di una classe è un'entità non generica e dotata di una sua
ben precisa entità. Questa entità fa parte dei dati prodotti dall'applicazione
software.
Es: se ho una classe Persona che tiene traccia del nome e del cognome di una
persona reale, le istanze di Persona saranno zone di memoria distinte dove
vengono memorizzate coppie di attributi nome e cognome: Mario Rossi,
Giuseppe Brambilla, Sandro De Pretis
Dove eravamo rimasti...
Nella seguente figura si cerca di riassumere il rapporto esistente tra le nostre
applicazioni e Spring:
Classe1
Classe2
3
<beans>
...
</beans>
.........
ClasseN
3
3
2
Spring
1
4
Applicazione generica
La
nostra
applicazione
invece
che
creare
istanze
delle
classi
(Classe1,Classe2,...ClasseN), le chiederà a Spring che farà da “intermediario” ( ossia
container) compiendo i seguenti passi:
1) il notro programma crea una nuova istanza di classe contesto Spring
indicandole il file xml da caricare per costruire i nostri bean.
2) Il contesto carica il file xml contente le istruzioni su quali istanze caricare in
esso
3) In base al file xml letto il contesto crea una sorta di indice delle istanze che
può restituire (istanze di Classe1, Classe2,...ClasseN e così via).
4) la nostra applicazione chiede al contesto una delle istanze configurate.
Andrea Del Bene – Spring core
2 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Visto che il miglior modo per imparare è "toccare con mano" faremo subito dei test di
caricamento del contesto da file xml. Spring per nostra fortuna ci fornisce delle classi
speciali di test unit basate su JUnit, in modo che possiamo usare questo potente
framework di test ed Eclipse per eseguire le nostre prove.
Progetto di test.
Assieme a questo tutorial si può scaricare un progetto da importare in Eclipse con il
quale eseguire le prove illustrate. Il progetto è distribuito come semplice file zip. Per
importarlo dal menù file scegliere “Import...”:
Immagine 1: Comando Import dal menù file
Successivamente ci verrà richiesto che tipo di risorsa importare. Bisogna scegliere
“Existing Projects into Workspace”:
Immagine 2: Scegliere la risorsa da importare
Andrea Del Bene – Spring core
3 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Immagine 3: La finestra finale di importazione
Ora come ultimo passo bisogna indicare al wizzard il file zip da importare
(SpringTutorial.zip) e scegliere il progetto da importare (progetto SpringTutorial):
Nota: se esiste già un progetto di nome SpringTutorial nel workspace non sarà
possibile importarlo!
Il plugin SpringIDE
Per lavorare con i file xml e Spring e pressoché indispensabile installare su Eclipse il
plugin SpringIDE. Questo mini-ide specifico per Spring è un sottoprogetto di Spring
stesso ed è curato sempre da membri dell' Interface21, l'azienda madre di Spring.
L'installazione segue la procedura standard di installazione dei plugin Eclipse. Se non
si conosce tale procedura si consulti il tutorial su Eclipse dalla slide 12 o il sito di
SpringIDE.
L'url
da
inserire
per
l'update
site
di
springIDE
è
http://springide.org/updatesite/.
L'uso del plugin verrà discusso in seguito.
Andrea Del Bene – Spring core
4 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
File di context.
Una volta importato il progetto apriamo il file jug4tendaContext.xml che rappresenta
il file di contesto che passeremo a spring per fare i nostri test con Spring.
Immagine 4: Il file di contesto
jug4tendaContext.xml
In questo tutorial il file di contesto sarà molto semplice:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="persona" class="org.jugancona.jug4tenda.domain.Persona">
</bean>
</beans>
Come possiamo vedere il tag radice del file è <beans>. Come si intuisce dal nome
all'interno di esso vi saranno le dichiarazioni dei bean che vogliamo inserire nel
contesto. La dichiarazione di un bean è contenuta nel tag <bean>. Il punto di
partenza della dichiarazione di un bean è l'attributo class del tag bean.
Con questo attributo indichiamo di quale classe sarà istanza il bean che stiamo
dichiarando.
Andrea Del Bene – Spring core
5 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Es: in sostanza scrivere class="org.jug4tenda.domain.Persona" equivale a scrivere
l'istruzione new Persona();
Un altro attributo usatissimo nel tag <bean> è id. id è una stringa che rappresenterà
l'identificativo che useremo per recuperare tramite Spring il bean che stiamo
costruendo. Il recupero del bean viene fatto il metodo getBean(idBean) esposto dal
contesto di Spring.
Es: getBean(“persona”) ci farà recuperare l'istanza della classe Persona configurata
nel file xml ed identificata dalla stringa “persona”. Da notare che getBean(...)
restituisce un tipo generico Object, e occorrerà quindi fare un cast al tipo voluto per
utilizzare l'istanza ottenuta. Es: (Persona)getBean(“persona”)
La classe di test.
Ora passiamo al codice della classe da test fornita con il progetto. Si trova sotto il
package org.jugancona.jug4tenda.tes e il codice è il seguente:
Immagine 5: Codice della classe di test
La classe estende AbstractDependencyInjectionSpringContextTests appartenente a
Spring e presente nel package org.springframework.test. E' una classe di utilità che
ci permette di fare test unitari caricando il contesto Spring. Si noti il metodo
getConfigLocation() dove specifichiamo la posizione del file xml di configurazione da
caricare (in realtà possiamo indicare più di un file xml...).
Il secondo dei due metodi presente nella classe di test è testSameInstance(). E' un
metodo di test con un nome arbitrario fatta eccezione per il suffisso test che fa in
modo che il framework JUnit lo eseguirà quando lanceremo il test.
Andrea Del Bene – Spring core
6 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Osservando le poche righe del metodo di test dobbiamo
a questo punto
familiarizzare con un concetto fondamentale in spring: le istanze dei bean ottenute da
Spring (la chiamata getBean(“...”)) sono create per default una ed una sola volta
(pattern singleton).
Il concetto è semplice ma chiariamolo con un esempio: se nel mio programma
richiedo a Spring un bean che avevo già richiesto in passato (stesso id passato a
getBean(“...”)), spring mi restituisce sempre la stessa istanza creata la prima volta,
ossia non riesegue un new sul bean.
L'esempio appena descritto è riscritto esattamente nel codice di testSameInstance() :
Immagine 6: Codice di testSameInstance
La nostra classe di test eredita dalla classe madre l'oggetto applicationContex che
rappresenta il contesto caricato da xml dalla classe al momento della sua costruzione.
Come si può vedere la variabile p di tipo Persona è valorizzata con l'istanza vuota
configurata in spring della classe Persona. Tramite p impostiamo la proprietà nome
poi impostiamo p a null perdendo il riferimento all'istanza.
Per dimostrare che Spring tratta le istanze configurate come singleton riotteniamo il
bean “persona” dal contesto e dichiariamo che la sua proprietà nome ha lo stesso
valore di prima.
Andrea Del Bene – Spring core
7 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Eseguire la classe di test.
Ora vediamo come eseguire la classe di test all'interno di Eclipse. Basta fare click
con il tasto destro e scegliere “Junit Test” dal menù “Run As” come mostrato in
figura:
Immagine 7: Esecuzione della classe di test
Il lancio di una classe di test JUnit mostra automaticamente la vista relativa di
Eclipse che ci accoglie con la riga verde, segno che il test è andato a buon fine:
Immagine 8: Il nostro test ha avuto successo
Andrea Del Bene – Spring core
8 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Le proprietà dei <bean>
Per concludere la nostra intrudizione a Spring, vedremo come valorizzare
direttamente nel file xml le proprietà delle istanze in esso configutrate. Iniziamo con
la valorizzazione delle proprietà base (numeri, stringhe e date). Per questo gruppo di
tipi primitivi si segue la seguente sintassi:
<beans>
...
<bean id="idBean" class="classeBean">
...
<property name="propertyName">aValue</property>
...
</bean>
...
</beans>
Si tratta in sostanza di usare il tag <property> innestato dentro <bean>. Questo tag
presenta l'attributo name che identifica la proprietà della classe che stiamo
valorizzando. Si può usare anche la forma contratta:
...
<property name="cognome" value="rossi" />
...
L'ultimo aspetto da esplorare ora è la valorizzazione di proprietà non primitive,
ovvero proprietà di tipo arbitrario. La valorizzazione di queste proprietà non può
essere fatta come appena visto poichè i loro valori sono oggetti complessi, non
esprimibili tramite caratteri alfanumerici. prendiamo come esempio il package
domain del nostro progetto Jug4Tenda. Vogliamo configurare nel nostro contesto
un'istanza di classe Indirizzo. Nel nostro dominio un Indirizzo deve essere sempre
associato ad una Persona (solitamente un Ospite) e non puà esistere senza un
riferimento ad essa:
In questi casi (comunissimi!) la proprietà è valorizzata referenziando un altro bean
configurato nel file xml tramite la seguente sintassi (in grassetto):
<beans>
...
<bean id="persona" class="org.jugancona.jug4tenda.domain.Persona">
...
<bean id="indirizzo" class="org.jugancona.jug4tenda.domain.Indirizzo">
...
<property name="ospite" ref="persona"/>
</bean>
</beans>
In sostanza si usa l'attributo ref, valorizzato con l'id bean desiderato.
Andrea Del Bene – Spring core
9 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
Una pausa di riflessione: IoC e DI
Come abbiamo appena visto attraverso il file di configurazione oltre a specificare
delle istanze di classe, possiamo anche indicare (con il costrutto ref="...") la relazione
che esiste fra di esse e come vanno "legate" (wired in inglese) l'una con l'altra. Ci
penserà poi Spring a costruire queste istanze tenendo conto delle dipendenze
indicate.
Nel nostro caso Spring si occuperà di costruire l'istanza indirizzo legandola a quella
di persona. Tutto ciò è un semplice esempio di Inversio Of Control (abbreviato
come IoC). Nel nostro caso concreto IoC significa che non sarà l'istanza di Indirizzo a
doversi preoccupare di soddisfare la sua dipendenza da un'istanza di Persona, ma
sarà Spring ad occuparsi di farlo.
L'IoC è molto efficace perchè ci evita di scrivere tutto quel codice che si usa per
"saldare" un'istanza ad un'altra. Es:
Class1 classeUtile = new Class1();
Class2 classeDipendeDaClass1 = new Class2();
...
//”saldo” classeUtile dentro classeDipendeDaClass1
classeDipendeDaClass1.setClass2(classeUtile);
Questa impostazione dei "legami" (delle dipendenze...) tra le due classi con Spring
viene fatta in maniera dinamica in base a quanto scritto nel file di contesto. Non
esiste più quella "saldatura" statica che lega a tempo di compilazione le istanze.
Questo aspetto che forse inizialmente sembra poca cosa, dimostra tutta la sua
potenza quando le dipendneze di una classe sono rivolte ad una interfaccia e noi
possiamo cambiarne l'implementazione semplicemente agendo sul file xml di
configurazione.
Altro vantaggio di questo approccio è che incentiva la progettazione del software in
moduli indipendenti e intercambiabili (una sorta di plugin per intenderci...) più
facilmente testabili e riutilizzabili.
A questo punto possiamo affrontare serenamente un'altra sigla ricorrente
nell'universo Spring, la Dependency Injection (DI). In realtà di DI ne abbiamo
parlato sino ad ora dicendo che nel modello IoC di Spring è il container di Spring che
di occupa di soddisfare le dipenze (DI appunto...) delle istanze "legandole" insieme.
La DI non è altro che la dipendenza tra due entità impostata nel file di
configurazione xml.
Fino
ad
ora
abbiamo
usato
una
DI
basata
sui
metodi
setter
(set<ClasseDaCuiDipendo>).
Dei setter si è parlato nel corso del primo capitolo introduttivo di questo tutorial.
E'utile ricordare che la DI oltre che con i setter si può fare anche con i costruttori di
classe qualora la nostra classe debba necessariamente configurarsi al momento della
sua costruzione.
Andrea Del Bene – Spring core
10 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
In futuro vedremo degli esempi di questo costrutto. Per ulteriori informazioni sulle
verie modalità tramite cui effettuare la DI si rimanda alla documentazione ufficiale di
Spring.
Il introduzione al plugin SpringIDE
NOTA: Assicuriamoci di aprire i file xml con l'editor xml di Eclipse come mostrato in
figura e non con qualche altro editor di qualche altro plugin(ad esempio Amateras),
altrimenti non si potrenno usare le funzioni descritte di seguito!
Immagine 9: Apriamo il file xml con l'editor
opportuno.
Andrea Del Bene – Spring core
11 / 12
Java User Group Marche
http://www.jugancona.org – [email protected]
La funzione più interessante offerta dal plugin è l'autocompletamento nell'attributo
class del tag <bean> e dell'attributo del tag <property>. Con SpringIDE è possible
attribuire una classe ad un istanza usufruendo del completamento automatico (ctrl +
spazio) del nome package e del nome classe, risparmiandoci tempo e tanti errori
frustranti. La stessa cosa vale per i nomi delle proprietà di classe che vogliamo
valorizzare.
Immagine 10: Proposta delle proprietà di
Indirizzo
I nomi ci vengono proposti in automatico. Anche i tag <bean> o <property> vengono
proposti in una lista sensibile al contesto, che ci propone solo le alternative
sintatticamente corrette. Vi rimando ancora una volta al wiki del plugin dove vengono
mostrati screenshot di quanto appena descritto
SpringIDE effettua anche la validazione del nostro file xml ogni volta che lo salviamo,
per scoprire in anticipo eventuali errori presenti in esso. Per ulteriori informazioni ed
approfondimenti su questo utilissimo strumento vi rimando all'indice del wiki, molto
completo ed esaustivo.
Andrea Del Bene – Spring core
12 / 12