Utilizzo di Spring in JSF 2.0

Introduzione

Nel post Utilizzo di CDI in JSF 2.0 abbiamo visto come utilizzare la Dependency Injection, resa disponibile dal framework J2EE nella specifica JSR-299, ed implementata in JBoss Weld. In particolare abbiamo visto come integrarla con JSF 2.0. In questo articolo seguiremo un percorso analogo per integrare l’IoC Container fornito dalla componente core del framework Spring, descritto nel post Primi Passi con Spring (core).

Una caratteristica fondamentale di Spring è quella di essere un framework che non forza il programmatore all’utilizzo di una particolare architettura o tecnologia o metodologia di sviluppo. Questo è particolarmente evidente nell’ambito delle applicazioni web in cui Spring fornisce un suo framework di riferimento (Spring MVC) ma, nonostante ciò, continua a supportare l’integrazione con altri popolari framework per il web, ed in particolare con JSF.

Come progetto di esempio utilizzeremo lo stesso progetto employees già descritto in diversi post, in particolare in Create Web App con BootstrapUtilizzo di CDI in JSF 2.0. Si tratta di un progetto web creato con Maven e configurato per essere eseguito sull’application server WildFly di JBoss.

Configurazione del POM

Per utilizzare Spring con JSF configuriamo innanzitutto le dipendenze nel file pom.xml del nostro progetto employees di esempio.

Spring Container

Tipicamente in una architettura web esiste uno strato di presentazione, composto dalle interfacce utente e dai bean di interazione con esse, ed uno strato di back-end, che fornisce servizi di business specifici e l’accesso ai dati. In Spring questo layer esiste all’interno di un contesto di business specifico che non contiene alcun elemento di presentazione indicato col nome di business context. Anche in Spring MVC, ad esempio, esiste un contesto distinto che è specifico del layer di  presentazione denominato presentation context.

Vediamo ora come  configurare il container di Spring per il contesto di business. Si noti che questo passo di configurazione non è specifico dell’integrazione con JSF, infatti si applica a tutti i framework web, incluso Spring MVC. A tale scopo tutto ciò che dobbiamo fare è quello di dichiarare il listener ContextLoaderListener nel file web.xml della propria applicazione web, e aggiungere una sezione <context-param> (nello stesso file) che definisce quale set dei file XML devono essere utilizzati per la configurazione di Spring.

Se non si specifica il parametro contextConfigLocation, il ContextLoaderListener cercherà un file chiamato /WEB-INF/applicationContext.xml da caricare. Una volta che i file di contesto vengono caricati, Spring crea un oggetto WebApplicationContext in base alle definizioni dei bean e lo memorizza nella ServletContext dell’applicazione web. L’accesso al business context avviene quindi recuperando l’ApplicationContext creato dal ContextLoaderListener e memorizzato nel ServletContext:

Integrazione con JSF

La componente chiave per l’integrazione con JSF di Spring è la classe SpringBeanFacesELResolver. Si tratta di un JSF compliant ELResolver che delega la risoluzione delle espressioni EL al business context di Spring (WebApplicationContext ) e solo successivamente all’implementazione JSF. Per farlo utilizziamo il file faces-config.xml:

Per proseguire con la configurazione del nostro progetto possiamo seguire due strade: utilizzare i file XML o le annotazioni. Vediamo nel dettaglio entrambe i casi.

Utilizzo degli XML

In questo caso utilizziamo i file faces-config.xml ed applicationContext.xml per definire rispettivamente i managed bean gestiti dall’IoC context di JSF ed i bean gestiti da Spring. Iniziamo quindi con Spring e definiamo il servizio EmployeeService:

Quindi utilizziamo il bean così definito per iniettarlo nel managed bean employeeManagedBean che andremo a configurare in faces-config.xml nel modo seguente:

Diversamente dal caso di integrazione con CDI, nella classe EmployeeManagedBean dovrà essere presente un metodo setter utilizzato dal resolver di Spring per iniettare il bean employeeService.

Il codice sorgente dell’applicazione è disponibile in sping employees. Una volta deployata su WildFly aprite il browser all’indirizzo http://localhost:8080/sping-employees/.

Utilizzo delle Annotazioni

Se preferiamo utilizzare le annotazioni al posto dell’xml per la configurazione del nostro progetto, modifichiamo innanzitutto il file applicationContext.xml di Spring per configurare l’autoscan:

Quindi annotiamo la classe EmployeeService con @Service per farla diventare un bean gestito dal contesto IoC di Spring.

Ed infine annotiamo EmployeeManagedBean con le annotazioni @ManagedBean e @SessionScoped (avendo cura di rimuovere la definizione del bean nel file faces-config.xml) per definirle come componente managed di JSF. A queste annotazioni va aggiunta @Component, che rende il bean “visibile” anche a Spring e l’annotazione @Autowired per indicare a Spring il punto di iniezione del bean employeeService. La classe si presenta quindi così:

Si noti che analogamente a CDI utilizzando @Autowired non vi è necessità del metodo setter.

Il codice sorgente è disponibile in sping employees. Una volta deployata su WildFly aprite il browser all’indirizzo http://localhost:8080/sping-employees/.

In realtà l’utilizzo misto delle annotazioni @ManagedBean e @Component non è necessario. In particolare l’annotazione JSF può essere rimossa e l’esempio funziona ugualmente. Ovviamente questo rende il bean non più gestito dal’IoC di JSF che quindi non potrà essere iniettato in un altro managed bean se non da Spring. Le interfacce continuano a funzionare perché il resolver che abbiamo definito nel file faces-config.xml accede innanzitutto al contesto di Spring per la risoluzione delle espressioni.

JSR-330

Dalla versione 3.0, Spring offre il supporto allo standard JSR-330. Questo implica che è possibile utilizzare l’annotazione @Inject al posto di @Autowired e @Named al posto di @Component. Ciò rende l’applicazione più portabile verso altri ambienti.