Introduzione
Spring è una piattaforma di sviluppo open source per applicazioni enterprise. Le componenti core del framework possono essere utilizzate per lo sviluppo di applicazioni java di diverso tipo, ma è attraverso le sue estensioni che è possibile realizzare applicazioni enterprise basate sulla piattaforma J2EE. Gli ideatori di Spring intendevano semplificare lo sviluppo di applicazioni J2EE promuovendo corrette pratiche di programmazione favorendo un modello basato su pojo.
La caratteristica per la quale Spring è maggiormente riconosciuto è la sua implementazione della Dependency Injection che è uno degli aspetti fondamentali dell’Inversion of Control (IoC). Quando una classica applicazione java viene avviata, essa provvede anche alla creazione di tutti gli oggetti da cui dipende per poter eseguire il proprio compito. In modo semplicistico possiamo dire che nell’IoC avviene il contrario, ovvero è un IoC container esterno al programma che si occupa di iniettare le dipendenze al programma principale. Tali funzionalità sono implementate nella componente di Spring denominata Core Container, che si compone dei moduli descritti nel seguito.
- Il modulo core è la componente fondamentale del framework ed implementa la Dependency Injection;
- Il bean module fornisce le classi factory per l’istanziazione dei bean;
- Il modulo context, implementato al di sopra dei moduli core e bean, fornisce l’accesso a tutti i bean definiti in funzione dei relativi contesti;
- Il modulo SpEL fornisce un expression language per la manipolazione dei bean a runtime.
Creazione del Progetto
Creeremo un progetto con Spring 4.3.2 e Java 8, utilizzando il supporto offerto da maven. Per farlo è sufficiente aprire una schell dei comandi e recarsi nella cartella dove abbiamo intenzione di creare il nuovo progetto. Quindi possiamo eseguire l’istruzione seguente:
1 2 3 4 5 |
mvn archetype:generate -DgroupId=it.inspiredsoft.spring -DartifactId=SpringExample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false |
L’archetype maven-archetype-quickstart
crea un progetto di esempio maven che possiamo poi estendere come vogliamo. Importiamo il progetto su Eclipse e creiamo la cartella /src/main/resources che maven non ci ha creato. Questa cartella è gestita da maven e tutti i file al suo interno sono trattati come risorse che in fase di build vengono copiate nella cartella di output classes. Tale cartella ci servirà per la configurazione di Spring. Se preferite, cancellate la classe di esempio App.class
generata da maven.
Procediamo aprendo il file pom.xm
ed inserendo la dipendenza necessaria per Spring core.
1 2 3 4 5 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> |
Configurazione dei Bean
Creiamo il nostro primo bean che con un eccesso di fantasia chiamiamo HelloWorld, il cui codice è il seguente:
1 2 3 4 5 6 7 8 9 10 11 |
public class HelloWorld { private Message message; public void setMessage(Message message){ this.message = message; } public void printMessage(){ System.out.println("Your Message : " + message); } } |
Tale bean ha una dipendenza con un altro bean di tipo Message
che utilizza per stampare il messaggio:
1 2 3 4 5 |
public class Message { public String getMessage() { return "Hello World!"; } } |
Quindi creiamo il file beans.xml
nella cartella resources
ed inseriamo il seguente xml, nel quale sono definiti e configurati i due bean helloBean
e messageBean
rispettivamente di tipo it.inspiredsoft.spring.HelloWorld
e it.inspiredsoft.spring.Message
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="messageBean" class="it.inspiredsoft.spring.Message"/> <bean id="helloBean" class="it.inspiredsoft.spring.HelloWorld"> <property name="message" ref="messageBean"/> </bean> </beans> |
messageBean
nella proprietà message
del bean helloBean.
A questo punto creiamo il seguente Main
di esempio:
1 2 3 4 5 6 7 8 |
public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); HelloWorld hw = (HelloWorld) context.getBean("helloBean"); hw.printMessage(); } } |
main
come semplice applicazione java ed otterremo in output:
1 |
Your Message : Hello World! |
Utilizzo delle Annotazioni
A partire dalla versione 2.5 di Spring è possibile configurare le dependency injection utilizzando le annotazioni al posto dell’XML. Per farlo modifichiamo il file beans.xml
nel modo seguente, eliminando la definizione dei bean ed introducendo il tag component-scan
che indica a Spring di scansionare il codice alla ricerca delle annotazioni che qualificano i bean, a partire dal package it.inspiredsoft:
1 2 3 4 5 6 7 8 9 10 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="it.inspiredsoft" /> </beans> |
1 2 3 4 5 6 |
@Component(value="helloBean") public class HelloWorld { @Autowired private Message message; .... } |
1 2 3 4 |
@Service public class Message { .... } |
Le due annotazioni @Component
e @Service
appartengono a Spring ed indicano al container che le due classi sono dei bean da inserire nel contesto del container IoC. L’annotazione @Autowire è invece quella che indica al container di iniettare il bean Message
nella proprietà message
del bean HelloWord
.
Eseguendo il main otteniamo esattamente lo stesso risultato.
Tipi di Annotazioni
Utilizzare le annotazioni piuttosto che l’XML con Spring ha naturalmente i suoi vantaggi e svantaggi. Innanzitutto molti “puristi” ritengono che con l’uso dell’XML è mantenuto separata la dichiarazione dei bean dalla loro configurazione. Inoltre con le annotazioni non è possibile configurare bean con nomi diversi ma dello stesso tipo. Infine l’XML rende più intuitivo l’iniezione di tipi primitivi. Per grandi applicazioni però, l’uso dell’XML può risultare tedioso o comunque difficoltoso da seguire per ricostruire il comportamento attesi dall’applicazioni. Per questo motivo molti sviluppatori sono maggiormente orientati verso la configurazione di Spring attraverso l’utilizzo delle annotazioni. Ma vediamo nel dettaglio quali sono le annotazioni supportate da Spring limitatamente alla componente core.
Stereotype Annotation
Queste annotazioni sono utilizzate per definire la “funzione” che il bean ha rispetto al layer applicativo cui appartengono. Classi annotate con questi stereotipi sono automaticamente gestite nell’IoC container di Spring.
ANNOTAZIONE | USO | DESCRIZIONE |
---|---|---|
@Component |
Type | Componente generico applicabile a qualsiasi bean. |
@Controller |
Type | Definisce il componente come uno controller di Spring MVC. |
@Repository |
Type | Indica che il componente è utilizzato per l’accesso ai dati. inoltre indica che una eccezione di tipo SQLExceptions sollevata dal componente deve essere tradotta in una Spring DataAccessExceptions. |
@Service |
Type | Indica che il componente rappresenta un service. |
Context Configuration Annotation
Queste annotazioni sono utilizzate da Spring per guidare la creazione e l’iniezione dei bean.
ANNOTAZIONE | USO | DESCRIZIONE |
---|---|---|
@Autowired |
Constructor, Field, Method | Utilizzato per annotare un costruttore, una proprietà, un metodo setter o uno configuration indica, un punto di iniezione per tipo. Gli item annotati con @Autowired non devono essere necessariamente pubblici. |
@Order |
Type, Method, Field | Definisce l’ordine di iniezione dei bean associati ad un array o collection. |
@Qualifier |
Field, Parameter, Type, Annotation Type | Consente di risolvere l’ambiguità che si avrebbe in fase di iniezione nel caso in cui esistessere due bean dello stesos tipo. |
@Required |
Method (setters) | Indica che una particolare proprietà deve essere iniettata o altrimenti la configurazione fallirebbe. |
@Scope |
Type | Specifica lo scope di un bean. Valori possibili sono: singleton, prototype, request, session, o un qualche custom scope. |