Home
 
Utilizzo combinato di Spring, Hibernate e EJB/JPA nel contesto enterprise PDF Stampa E-mail
Scritto da Douglas Oviche   
Venerdì 24 Febbraio 2012 17:37

Utilizzo combinato di Spring, Hibernate e EJB/JPA nel contesto enterprise

L'articolo che state per consultare è il risultato di una estenuante ricerca di combinazione ed assemblaggio di specifiche e framework basate su tecnologia Java.
Lo scopo di questa ricerca è stato realizzare un applicativo distribuito utilizzando le cutting edge technologies o tecnologie all'avanguardia.
Quando si parla di tecnologie all'avanguardia nell'ambiente java, il pensiero ci porta immediatamente alle specifiche J2EE, ma soprattutto alle specifiche principali che ne fanno parte come EJB e JPA. Oltre a queste specifiche, ci sono delle piattaforme e framework che implementano meccanismi di iniezione DI e IOC con il supporto di sistemi e provider di persistenza che inizialmente possono risultare difficili da configurare per le nostre particolari esigenze, ma, nel corso dello sviluppo di un progetto di complessità media o alta, possono portare dei vantaggi significativi accelerando il rilascio dei diversi moduli architetturali che costituiscono il sistema.
Personalmente mi sono sempre domandato come abbinare i framework spring, hibernate, jpa e gli enterprise java beans, affinché potessi ottenere il massimo da ognuna di queste tecnologie all'avanguardia.
Ad esempio, mi sono chiesto come potevo fare per riuscire a fornire una totale configurazione dei miei componenti di servizio, persistenza (ecc...) tramite il framework spring e soprascrivere il meccanismo di iniezione svolto dagli intercettori forniti nella specifica EJB, permettendo a quelli di spring di subentrare in questo processo.
Un'osservazione importante che riporto in questo articolo sono gli aspetti relativi alla normalizzazione delle banca dati: spesso ci imbattiamo nella progettazione di entità di persistenza in JPA, senza mai prendere in considerazione la normalizzazione presente nel sistema relazionale. Non bisogna mai dimenticare che tale normalizzazione deve essere estesa nel contesto applicativo, altrimenti commettiamo un gravissimo errore di progettazione.
Dunque, l'intenzione dell'articolo è spiegare come avviene la progettazione di questo mix tecnologico tramite un pratico esempio applicativo che è possibile verificare scaricando il file compresso e provando voi stessi.
Attualmente la soluzione è stata da me collaudata su glassfish, ma nulla impedisce la possibilità di schierare l'applicazione su JBoss od altri AS con supporto EJB container.

Pre requisiti:
Glassfish 3v
Jdk 1.6 o +
Hibernate 3 o +
Springframework qualsiasi versione
Specifiche J2EE (EJB 3.0, JPA 1.0/2.0)

Struttura del progetto:

Struttura del progetto

Intefaccia DAO:

package com.soluzionijava.sample.dao;

public interface ClienteDAO {
	
	public Cliente findCliente(BigInteger idCliente);
	
	public List
 findPagamentiByIdCliente(BigInteger idCliente);	
}

L'implementazione dell'interfaccia ClienteDAO:

package com.soluzionijava.sample.dao;

public class ClienteDAOImpl implements ClienteDAO {
	@PersistenceContext
	private EntityManager em;
	
	@Override
	public Cliente findCliente(BigInteger idCliente) {
		
		Cliente cliente = null;
		String namedQuery = "findClienteById";
		
		try {
			Query query = em.createNamedQuery(namedQuery);
			query.setParameter(1, idCliente);
			cliente = (Cliente)query.getSingleResult();		
		} catch (NoResultException e) {
			cliente = null;
		}
		
		return cliente;
	}
	…...........
}

Ci sono degli elementi che spiccano all'interno di questa implementazione, uno di questi è l'utilizzo dell'annotazione @PersistenceContext: tale annotazione mette a disposizione nella nostra implementazione DAO l'elemento JPA EntityManager. Tramite l'EntityManager vengono effettuate tutte le operazioni d'accesso al dato come ad esempio:
javax.persistence.Query query = em.createNamedQuery(namedQuery);
Viene trovato il Cliente per id tramite JPA EntityManger che a sua volta attraverso il metodo createNamedQuery ci permette di effettuare l'esecuzione di EJB QL.
In questo particolare esempio viene utilizzato quello per le invocazioni delle query nominate ossia namedQuery fornite nell'entità coinvolta nell'operazione, ma, questo prototipo applicativo, non si sofferma sui particolari di JPA, ma bensì sulla progettazione di quest'insieme di tecnologie.
Osserviamo un po' più da vincino l'entità Cliente, entità principale nel nostro articolo:

package com.soluzionijava.sample.entity;

@Entity(name="Cliente")
@Table(name="clienti")
@NamedQuery(name="findClienteById",
query="select o from Cliente o where o.id = ?")
public class Cliente implements java.io.Serializable {

	@Id
	private BigInteger id;

	@Column(name="COGNOME", nullable=false)
	private String cognome;

	@Column(name="NOME", nullable=false)
	private String nome;

	@OneToMany(fetch=FetchType.EAGER, mappedBy="cliente")	
	private Set<RClientiPagamenti> clientiPagamenti;	

	[…]
}

Il frammento di codice di sopra riportato ci mostra l'entità Cliente con i suoi diversi campi(Field), i setters e getters sono stati omessi, ma devono essere obbligatoriamente presenti.
• Prima osservazione: @Entity(name="Cliente"). Questa dichiarazione annotata determina che ovunque verrà utilizzata questa entità dovrà essere chiamata con questo nome.
• Seconda osservazione: @Table(name="clienti"). Correla l'entità ad una tabella relazionale.
• Terza osservazione: @NamedQuery(name="findClienteById", query="select o from Cliente o where o.id = ?"). Definisce ed associa all'entità una NAMED_QUERY.
• Quarta osservazione: ogni singolo campo viene associato ad un campo di una tabella relazionale.

File di configurazione ORM:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
	

		

			<access>FIELD</access>
		</persistence-unit-defaults>
	</persistence-unit-metadata>
</entity-mappings>

Andando avanti nel nostro mix tecnologico, arriviamo finalmente al servizio e cioè l'enterprise java bean che viene iniettato da spring con l'implementazione del nostro DAO.

package com.soluzionijava.sample.service;

@Stateless(mappedName="ClienteService", name="ClienteService")
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class ClienteService implements ClienteServiceRemote, ClienteServiceLocal {
	@Autowired
	private ClienteDAO clienteDAO;

	[…]
	
	@Override
	public Cliente findCliente(BigInteger idCliente) {
		return clienteDAO.findCliente(idCliente);
	}

	@Override
	public List
 findPagamentiByIdCliente(BigInteger idCliente){
		return clienteDAO.findPagamentiByIdCliente(idCliente);
	}

	[…]
}

In questa classe ci sono due elementi di fondamentale importanza, ma discutiamoli uno alla volta affinché tale importanza possa essere capita esaustivamente.
In questo componente avviene la vera manifestazione di mischia tecnologica promessa in questo articolo: se guardiamo con attenzione possiamo osservare che gli intercettori vengono sovrascritti con quelli del framework spring @Interceptors(SpringBeanAutowiringInterceptor.class).
Una volta che spring è subentrato nel meccanismo di iniezione, lungo il corpo della classe possono essere osservate le sue manifestazioni attraverso l'utilizzo dell'annotazione @Autowired.
Per completare è rendere finalmente possibile questo mix, bisogna però fornire le configurazioni contestuali che mettono a disposizione l'intero meccanismo di intercezione ed iniezione(DI/IOC).
Una volta che i nostri componenti java sono pronti per l'uso, bisogna portare nel contesto applicativo una serie di file.
Di seguito vi elenco i file mancanti che chiudono il puzzle:

Il file beanRefContext.xml

<beans>
    <bean class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg value="classpath*:soluzionijava-enterprise.xml" />
    </bean>    
</beans>

Questo file definisce le factory nel contesto business, in effetti viene usato dagli ejb per usufruire dei beans e pojo definiti nel contesto business.
Il file soluzionijava-enterprise.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<import resource="classpath*:soluzionijava-dao.xml"/>			
	<context:annotation-config/>
	<tx:annotation-driven />	
</beans>

Il file soluzionijava-dao.xml

<beans>	
	<bean id="clienteDAO" class="com.soluzionijava.sample.dao.ClienteDAOImpl" 	autowire="byName"/>
	
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
	
	<bean id="entityManagerFactory" 	class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		

	</bean>
	
	<bean id="transactionManager" 	class="org.springframework.orm.jpa.JpaTransactionManager">
		

	</bean>
	
	<context:component-scan base-package="com.soluzionijava.sample.entity" />
	<tx:annotation-driven />
	</beans>

Per l'ultimo il file di persistenza:
persistence.xml

< persistence-unit name="soluzioniJava" transaction-type="RESOURCE_LOCAL">
	< provider>org.hibernate.ejb.HibernatePersistence</provider>
	< class>com.soluzionijava.sample.entity.Cliente</class>
	< class>com.soluzionijava.sample.entity.RClientiPagamenti</class>
	< class>com.soluzionijava.sample.entity.Pagamento</class>
	< class>com.soluzionijava.sample.entity.RClientiPagamentiPK</class>
	
		< properties>
		< property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
		    < property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/clienti_db"/>
		    < property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
		    < property name="hibernate.connection.username" value="root"/>
		    < property name="hibernate.connection.password" value="password"/>
		< /properties>
	< /persistence-unit>
< /persistence>

Promemoria:
Ricordate di includere nelle intestazioni dei file di configurazione i diversi schemi che occorrono per portare nel contesto applicativo le capacità dichiarate all'interno dei file.
Prima di salutarvi volevo ricordarvi che questo mix di tecnologie è stato da me collaudato e ed attualmente esistono dei progetti nei quali è stato già applicato.

Buon lavoro e al prossimo articolo

Douglas Oviche (doviche@gmail.com)

Scarica Sorgente

 

Condividi
Ultimo aggiornamento Lunedì 27 Febbraio 2012 11:04
 

Commenti  

 
0 #3 Giuseppe 2012-03-05 00:32
Ciao ho seguito la tua guida ma quando lo faccio partire sul server mi da un'eccezione del tipo "No persistence provider were found". Premetto che ho aggiunto al buildpath sia le hibernate-core che le hibernate-entitymanager. Sapresti darmi un mano? Grazie :)
Citazione
 
 
+2 #2 Isabella 2012-02-27 19:43
Articolo molto interessante!!!
Citazione
 
 
0 #1 Isabella 2012-02-27 12:36
Articolo molto interessante!
Citazione
 

Aggiungi commento


Codice di sicurezza
Aggiorna

Questo sito utilizza i cookie e tecnologie simili per consentire la corretta navigazione. To find out more about the cookies we use and how to delete them, see our privacy policy.

I accept cookies from this site.

EU Cookie Directive Module Information