Spring-01 – Introduzione al framework Spring

S

INTRODUZIONE

 

nuova linea editoriale in italiancoders

Ciao Coders,

con questo articolo siamo lieti di annunciare una nuova linea editoriale sul framework Spring. L’obbiettivo è quello di partire dalle basi e esplorare questo fantastico framework nelle sue funzionalità e caratteristiche. In questo articolo vedrete poco “codice” poiché è introduttivo e sarà focalizzato sui core concept di Spring in modo da avere una infarinatura generale prima di andare nello specifico. Potrà risultare quindi anche noioso per alcuni questo articolo ma è bene ripassare con gli inesperti concetti come MVC, Dependency Injection ed altri poiché sono alla base di questo framework. L’errore comune è sempre quello di fiondarsi a capofitto su Spring senza avere le basi.

I requisiti tecnici di questa serie di articoli sono una buona conoscenza del mondo Java JSE; inoltre è apprezzato anche un minimo di conoscenza sul mondo JAVA JEE anche se non obbligatorio.

INTRODUZIONE

Consiglio ai neofiti di seguire questi articoli; con molta probabilità quando ti affaccerai sul mercato del lavoro sentirai molto parlare di Spring; il mercato italiano è molto focalizzato sullo sviluppo di software enterprise: ovvero di  software utilizzati per soddisfare le esigenze di un’organizzazione piuttosto che singoli utenti, di solito di grande dimensione e complessità; I servizi forniti da enterprise application software (EAS)  sono in genere strumenti orientati al business come ad esempio acquisti online e elaborazione dei pagamenti online, catalogo prodotti interattivi, sistemi di fatturazione automatizzati, sicurezza, gestione dei contenuti aziendali, , pianificazione delle risorse aziendali e altre realtà complesse. Spring è il considerato il “re” dei framework  per lo sviluppo di SW Enterprise; i motivi ? in questo articolo vi mostrerò una panoramica dei punti di forza di questo potentissimo framework.

SPRING

Nato come codice allegato al libro “Expert One-on-One J2EE Design and Development”,
Spring ha il chiaro intento di gestire la complessità legata allo sviluppo di
applicazioni enterprise.
La sua prima apparizione risale al 2003 sotto licenza Apache, ma fu solo nel marzo
del 2004 il primo importante rilascio, ovvero la versione 1.0; attualmente è giunto
alla versione 5.0.2  e viene definito come il più popolare framework per lo sviluppo di
applicazioni Java Enterprise. Visto come una valida, e ormai ben solida alternativa
al modello basato su Enterprise Javabeans, questo framework supera l’appesantimento
derivato dall’utilizzo forzato di interfacce EJB di tipo home e remote, troppo invasive nel codice scritto, pur mantenendo la possibilità di gestire il descrittore di  deployment in XML grazie a nuovi ed innovativi modelli di programmazione, come l’Aspect Oriented Programming (AOP) e l’Inversion of Control (IoC).
Spring è inoltre un framework leggero: grazie alla sua struttura estremamente modulare
è possibile utilizzarlo nella sua interezza o solo in parte, senza stravolgere
l’architettura del progetto; questa peculiarità permette una facile integrazione anche
con altri framework già esistenti, come Struts3 o Hibernate.4 Fornisce, inoltre,
una serie completa di strumenti per gestire la complessità dello sviluppo software,
fornendo un approccio semplificato sia più comuni problemi di sviluppo (accesso ai
database, gestione delle dipendenze, etc.) che di testing.

struttura modulare

Il framework Spring ha una struttura modulare:

  • il modulo core che fornisce le funzionalità fondamentali del framework. Tale modulo si basa sulle seguenti funzionalità e pattern: Dependency Injection, Aspect-Oriented Programming, la gestione delle transazioni, la struttura di applicazioni Web, l’accesso ai dati, la messaggistica, i test e altro.
  • Altri moduli facoltativi : dalla configurazione alla sicurezza, dalle web app ai big data. L’elenco completo dei moduli Spring li trovate al seguente LINK

La filosofia è quindi la seguente: Qualunque sia il supporto di cui hai bisogno esiste al 99.9% uno  Spring Project per aiutarti a costruirlo. Il mio consiglio è quello di partire in piccolo e usare solo ciò di cui si ha bisogno e aggiungere all’esigenza il modulo adatto.

Ho nominato Dependency Injection, Aspect-Oriented… per i neofiti questi due termini potrebbero risultare oscuri, pertanto cercherò di introdurli; in particolare in questo articolo tratteremo di Dependency Injection.

spring per il web

Come anticipato con Spring puoi fare veramente di tutto! Essendo vastissimo questo framework il nostro corso si focalizzerà sull’utilizzo di Spring per il WEB. Spring permette la progettazione e sviluppo di applicazioni web grazie al suo modulo Spring MVC il quale mette a disposizione le funzionalità core di Spring, accennate al paragrafo precedente, su un pattern architetturale MVC. L’errore più comune è buttarsi a capofitto a sviluppare in Spring senza conoscere MVC; ritengo quindi necessario un veloce ripasso di MVC.

Il Pattern MVC

Spesso, quando si implementa un’applicazione Web utilizzando la tecnologia Java, a
causa dell’utilizzo di un protocollo “povero” come HTTP si tende ad usare in modo
indiscriminato Servlet1 e pagine JSP. Se questo da un lato dà la possibilità di una maggiore flessibilità e libertà di programmazione, dall’altro può andare contro alle norme della qualità del software, come riusabilità, portabilità  e manutenibilità.

Per sopperire a tali esigenze, si è designata un’architettura per le Web application chiamata Model-View-Controller.
Tale è stata introdotta per la prima volta da Trygve Reenskaug nel tardo 1970, ma diventerà una pietra miliare per l’architettura di tutte le future applicazioni Web-based, poichè riesce brillantemente a separare tutta la logica business e la rappresentazione delle informazioni dalle interazioni utente con quest’ultime.
Tale modello è costituito sostanzialmente da 3 strati: la parte business formata da Model e Controller, e l’interfaccia utente (View). Nel dettaglio:

  • Model: Implementa la logica di business, fornendo i metodi utili per l’accesso ai dati
    dell’applicazioneed ha la responsabilità della gestione del database.
  • Controller: Implementa la logica di controllo, riceve i comandi dell’utente (in genere
    attraverso lo strato View) e li attua modificando lo stato degli altri due componenti.
  • View: Implementa la logica di presentazione, interpretando i risultati ottenuti da una
    dal Model e gestendo l’interazione con gli utenti.
    È importante far notare che sia lo strato View che lo strato Controller dipendono
    direttamente dal Model, il quale non dipende dagli altri. Questo è uno dei fattori
    più importanti di questa architettura, poiché permette al modello di essere implementato e testato indipendentemente dallo strato di visualizzazione.

Grazie a questi accorgimenti, molteplici sono i benefici derivati: grazie a tale approccio,
è possibile implementare viste multiple, permettendo l’esposizione degli stessi
dati allo stesso instante in modi diversi. Si riduce la complessità di sviluppo, e
conseguentemente il costo di aggiornamento, permettendo la manutenzione ad uno
degli strati senza coinvolgerne altri.

SPRING MVC VS SPRING BOOT

Oggi quando sentiamo parlare di Spring sentiamo spesso nominare Spring Boot. Ma cos’è Spring Boot? Una nuova versione di Spring? Chiariamo questa fatidica domanda una volta per tutte.
Posso facilmente dire che Spring Boot è il prossimo capitolo di Spring Framework. Non fraintendermi, però; Spring Boot non sostituirà il Spring Framework. Questo perché Spring Boot è il framework Spring! Spring Boot è un progetto Spring che ha lo scopo di rendere più semplice lo sviluppo e l’esecuzione di applicazioni Spring:

  • un’applicazione Spring può richiedere una gran quantità di metadati di configurazione – anche se si utilizzano componenti e autowiring
  • Spring Boot semplifica lo sviluppo delle applicazioni, poiché ne  effettua una configurazione automatica (ove possibile), sulla base di valori di default “intelligenti” – un’applicazione Spring Boot richiede, di solito, solo una configurazione minima
    • in questo, Spring Boot utilizza un approccio “opinionated”
      (“convenzionale”, basato su opinioni e convenzioni proprie)
    • le scelte di default possono essere comunque sovrascritte
      mediante configurazioni esplicite
  • Spring Boot fornisce inoltre delle opzioni per la costruzione (build) e il rilascio (deploy) delle applicazioni in produzione
  • Il risultato del build della tua applicazione Spring Boot sarà un standalone JAR file con al suo interno un embeded server. Questo vuol dire che non avrai bisogno di configurare un  servlet container come Tomcat o un Java EE server come Jboss per eseguire la tua applicazione; basterà eseguire il jar risultato della build e Spring boot tirerà su un embedded server che fungerà da container per la tua web application. Questo comporta un enorme vantaggio in risparmio di tempo e nello scalare la tua applicazione: il quale si tradurrà semplicemente in tirare su più istanze eseguendo il jar il tutto dietro ad un reverse proxy.

Per tutti questi motivi ho deciso di utilizzare Spring Boot come riferimento per i miei articoli.

inversion of control (IOC)

L’Inversion of Control è un principio architetturale nato alla fine degli anni ottanta, basato sul concetto di invertire il controllo del flusso di sistema (Control Flow) rispetto alla programmazione tradizionale. Nella Programmazione tradizionale lo sviluppatore definisce la logica del flusso di controllo, specificando le operazioni di creazione, inizializzazione degli oggetti ed invocazione dei metodi. Nell’ Inversion of Controlo (IOC)  si inverte il control flow, facendo in modo che non sia più lo sviluppatore a doversi preoccupare di questi aspetti, ma il framework, che reagendo a qualche “stimolo” se ne occuperà per suo conto.

Questo principio è anche conosciuto come Hollywood Principle
(“Non chiamarci, ti chiameremo noi”).

DEPENDENCY INJECTION (DI)

Il termine Dependency Injection (DI) è utilizzato per riferirsi ad una
specifica implementazione dello IoC:

  • DI è rivolta ad invertire il processo di risoluzione delle dipendenze,
    facendo in modo che queste vengano iniettate dall’esterno.
  • Esempio di “tight coupling”: Una classe A si dice dipendente dalla
    classe B se ne usa in qualche punto i servizi offerti.

    • Uso del costruttore
    •  Uso di una Factory
    •  Uso di un servizio di naming (lookup)

Per intenderci, Spring implementa la IoC tramite Dependency Injection.

La DI prevede che tutti gli oggetti all’interno della nostra applicazione accettino le dipendenze, ovvero gli (altri) oggetti di cui hanno bisogno, tramite costruttore o metodi setter. Non sono quindi gli stessi oggetti a creare le proprie dipendenze, ma esse vengono iniettate dall’esterno.

Spring IoC container

Spring ci facilita la vita creando e iniettando (al posto nostro) le dipendenze necessarie alle classi della nostra applicazione. Questo avviene sia per i componenti del framework, sia per gli oggetti da noi definiti.

L’ecosistema all’interno del quale le applicazioni Spring vivono viene definito IoC container. Lo IoC container si occupa di istanziare gli oggetti (beans) dichiarati nel progetto e di reperire e iniettare tutte le dipendenze ad essi associate. Tali dipendenze possono essere componenti del framework o altri bean dichiarati nel contesto applicativo.

La domanda sorge spontanea… come creare e gestire lo IoC container in Spring? Come Dichiarare i componenti e inniettare le dipendenze? Risponderò a tutte queste domande con un esempio.

il nostro primo progetto spring

Creiamo il nostro primo progetto Spring Boot; come ide potete utilizzare qualsiasi IDE; io utilizzo IntelliJ e lo reputo assolutamente il miglior IDE Java in circolazione; se volete optare su un IDE Open-Source vi consiglio Spring tool suite  una versione customizzata di Eclipe con molte facility per sviluppare su Spring. Sia Intellij, che Eclips o STS hanno la possibilità di utilzzare il servizio SPRING INITIALIZR il quale ti permette di generare un progetto Spring Boot pre-configurato specificando i moduli di cui hai bisogno. Lo staff di Spring mette a disposizione anche una web page per utilizzare il servizio SPRING INITIALIZR al seguente LINK .

Per il nostro primo progetto avremo bisogno del solo modulo default core senza altri moduli, poichè si tratta di un semplice main per mostrarvi l’uso di dependency injection. Quindi se usate Intellij accedete al menu File->New Project -> Spring Initializr

Editiamo  i metadata del nostro progetto Maven

E infine non spuntiamo nessun’altra dipendenza avendo bisogno solo del modulo core (PS: Potrete comunque aggiungere in un secondo momento ulteriori dipendenza editando il pom del vostro progetto)

e Infine confermate la creazione del vostro progetto

Il risultato pronto per essere sviluppato e già configurato eliminando l’overhead della configurazione di un progetto Spring MVC o JEE ( vi assicuro un calvario 🙂 )

Come potete vedere la configurazione minimale del progetto ha generato:

  • la folder java contenente la classe di Startup del progetto e il package su cui andremo a sviluppare le nostre classi
  • la folder test contenente il package delle classi dei nostri test
  • pom.xml : il descrittore che configura le direttive di build del progetto e le dipendenze. Se abbiamo bisogno di librerie o ulteriori moduli occorre aggiungere alle dependencies del pom il riferimento al repository della nostra dipendenza
  • resources: La cartella delle risorse è uguale alla cartella del progetto src. Tuttavia mira a memorizzare file .ico, .mp3, .xml, .properties, ecc. Del progetto. Questi sono file comuni usati nel progetto come application.properties che contiene le proprietà di configurazioni di spring o altre proprietà custom della nostra applicazione.

Andiamo adesso ad aprire DemoDiApplication.java la quale si presenta come una classe vuota con una annotation @SpringBootApplication  e  un metodo Main

public static void main(String[] args) {
  SpringApplication.run(DemoDiApplication.class, args);
}

SpringBootApplication è una annotation che importa a sue volte altre 3 Spring Annotation: @Configuration, @EnableAutoConfiguration e @ComponentScan . Esse sono le tre annotation che danno vita al nostro Spring Project. Analizziamo in dettaglio ognuna della annotation citate.

CONFIGURATION

Tale annotation indica che la classe dichiara uno o più metodi @Bean e può essere elaborata dal contenitore Spring per generare definizioni di bean e richieste di servizio per tali bean in fase di runtime. Ad esempio aggiungiamo alla nostra classe DemoApplication.java il seguente metodo

@Bean
List<String> studentList(){
  List<String> students = new ArrayList<>();
  students.add("pippo");
  students.add("pluto");
  
  return students;
}

L’annotazione @Bean , essendo all’interno di una classe @Configuration fungerà  da factory per il nostro bean. L’oggetto restituito dal metodo verrà quindi preso in carico dallo IoC container. Di default, tutti gli oggetti istanziati dal container sono disponibili come singleton; all’interno del nostro progetto avremo quindi una sola istanza di ogni bean. Questo comportamento, ovviamente, può essere configurato diversamente in base alle esigenze (scriverò un articolo su questo tema).

ENABLE AUTO CONFIGURATION

Abilitando la configurazione automatica,  Spring Boot tenterà di configurare automaticamente la tua applicazione Spring in base alle dipendenze jar che hai aggiunto. Ad esempio, se HSQLDB si trova sul classpath e non hai configurato manualmente alcun bean di connessione al database, Spring boot configurerà  automaticamente un database in memoria HSQLDB. Questa features è fantastica.

component scan

Quando sviluppi applicazioni Spring Boot, devi dire al Framework in che package cercare i componenti da gestire all’interno del IOC.  L’uso della scansione dei componenti automatica è una features per abilitare Spring a rilevare i componenti gestiti da Spring ovvero rilevare e istanziare componenti da package predefiniti. Se non specificato il package Spring attiva la component scan sul package corrente e i suoi sotto package.  Spring può eseguire automaticamente la scansione di tutte le classi annotate con le seguenti annotation @Component  e di alcune specializzazioni di esso che tratterò in un prossimo articolo (@Controller, @Service e @Repository). 

Torniamo nel nostro esempio, abbiamo appena detto che @SpringBootApplication, applicata alla main class del nostro progetto, abiliti una serie di funzionalità e configurazioni di default.

Tra le funzioni principali c’è il component scanning, ovvero la scansione del root package del progetto alla ricerca di tutte le classi marcate come componenti. Nel nostro caso andremo a creare un sotto package components e una nuova classe ReportExec marcata con l’annotation @Component . Spring innietterà il bean studentsList nella classe ReportExec, la quale lo utilizzerà per stampare a video gli studenti all’interno del bean studentsList .

@Component
public class ReportExec {
    
    @Autowired
    private List<String> studentsList;

    public void execute(){
        System.out.println("I nostri studenti sono");

        for(String student : studentsList){
            System.out.println("Nome:"+student);

        }
    }
}

che significa la nuova annotation @Autowired? L’annotazione @Autowired può essere applicata a diversi elementi della nostra classe: ad un campo, un metodo o un costruttore.
In ogni caso il suo compito è quello di indicare a Spring quali sono le dipendenze richieste da un determinato oggetto.
Queste vengono ricercate tra le istanze presenti nello IoC container e, se presenti, vengono iniettate mediante il costruttore o il metodo annotato. In breve in fase di runtime il comportamento di Spring sarà il seguente:

  • verrà istanziato il bean studentsList  essendo tale metodo annotato con @Bean all’interno di una classe @Config . Tale istanza verrá conservata nell’ IOC container del framework.
  • Essendo attivo il component scan, il framework inizierà a cercare all’interno dei package che hanno come radice  it.italiancoders.demodi  componenti da istanziare; creerà quindi una istanza del componente ReportExec essendo tale classe annotata con @Component. Quindi anche un istanza di ReportExec verrà inclusa nell IOC container.
  • L’istanza ReportExec  ha come dipendenza List<String> studentsList (essendo tale proprietà annotata con autowired). Per risolvere tale dipendenza il framework controllerà se esiste una istanza nell’IOC container candidata a risolvere tale dipendenza e la innietterà nel bean. Il bean candidato a risolvere questa dipendenza è sicuramente  studentsList. Il lettore più attento si chiederà come ha fatto Spring a sapere che il bean candidato per risolvere tale dipendenza era studentsList . I criteri utilizzati per risolvere le dipendenza sono in ordine :
    • Abbinamento per nome : Spring cerca un bean che si chiama esattamente con il nome della proprietà, Nel nostro esempio è bastato questo check per risolvere la dipendenza.
    • Abbinamento per tipo: Se non esiste un bean con quel nome, o se ne esistono più  di uno, Spring cerca un bean nell IOC container di quel tipo.
    • Abbinamento per  Qualifier: Se esistono piu’  di  bean di quel tipo, Spring cerca un bean nell IOC container di quel tipo e dichiarato con un apposito id. È possibile dichiarare formalmente un id di un bean utilizzando l’annotation @Qualifier insieme a @Bean. Quando si ha bisogno di ordinare l’inject di un bean con id X basterà annotare il campo con @Autowired(“X”).

Completiamo quindi il nostro esempio andando ad iniettare nel nostro main l’istanza di ReportExec  utilizzandola per stampare a video il report. Per fare questo modifichiamo DemoDiApplication.java :

  • Richiedo l inject di reportExec
@Autowired
ReportExec reportExec;
  • Dichiaro che la classe DemoApplication  implementa ApplicationListener<ApplicationReadyEvent> avendo cosi una callback che scatta dopo l’inizializzazione di Spring dove posso inserire il codice del mio esempio .

Il risultato è la seguente classe:

@SpringBootApplication
public class DemoDiApplication implements ApplicationListener<ApplicationReadyEvent> {

  @Autowired
  ReportExec reportExec;

  public static void main(String[] args) {
    SpringApplication.run(DemoDiApplication.class, args);
    
  }

  @Bean
  List<String> studentList(){
    List<String> students = new ArrayList<>();
    students.add("pippo");
    students.add("pluto");

    return students;
  }

  @Override
  public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
    reportExec.execute();

  }
}

Eseguendo il nostro progetto otterò quindi come atteso il seguente output dopo i post di log del core di Spring.

I nostri studenti sono
Nome:pippo
Nome:pluto

Potete scaricare il progetto esempio di questo articolo clonando la REPO GITHUB dei miei tutorial Spring al segunte url:
https://github.com/dario-frongillo/italiancoders-spring-tutorial
(l’esempio di questa lezione è nella sotto folder 1-ioc_di)

CONCLUSIONI

In questo articolo abbiamo:

  • introdotto il framework Spring
  • Ripassato concetti fondamentali come il pattern MVC utilizzato ampiamente dal framework Spring
  • Introdotta uno dei concetti alla base di tutto Spring: IOC e DI

Quale sarà il percorso di questa linea editoriale? Nei prossimi articoli completeremo la panoramica sulla Dependency Injection e proseguiremo con la spiegazione del secondo concetto fondamentale in Spring: Aspect oriented programming (AOP) . Una volta maturate le basi del framework vi spiegherò le best practices per strutturare un progetto MVC in Spring: focalizzandoci su una architettura REST, Cosa non troverete in  questa linea editoriale? Non tratterò molto il presentation layer su Spring; nonostante mi trovo benissimo con questo framework sono contrario ai monoliti e preferisco alle lunghe soluzioni scalabili che disaccoppiano backend e frontend come soluzioni RESTful con il backend in Spring e il frontend in Angular o React.

A proposito di me

Dario Frongillo

Uno degli admin di Italiancoders e dell iniziativa devtalks.
Dario Frongillo è un software engineer e architect, specializzato in Web API, Middleware e Backend in ambito cloud native. Attualmente lavora presso NTT DATA, realtà di consulenza internazionale.
E' membro e contributor in diverse community italiane per developers; Nel 2017 fonda italiancoders.it, una community di blogger italiani che divulga articoli, video e contenuti per developers.

Di Dario Frongillo

Gli articoli più letti

Articoli recenti

Commenti recenti