Spring en Modelo a Vanz a Do

57
Tema 4: Uso de Spring en la Capa Modelo

description

Spring y sus caracteristicas

Transcript of Spring en Modelo a Vanz a Do

Page 1: Spring en Modelo a Vanz a Do

Tema 4: Uso de Spring en la Capa Modelo

Page 2: Spring en Modelo a Vanz a Do

4 - 2

Índice

n  Introducción a Spring n  Declaración y Configuración de “beans” n  Excepciones de Persistencia n  Declaración de DataSources n  Integración con Hibernate 4 n  Gestión de Transacciones

Page 3: Spring en Modelo a Vanz a Do

4 - 3

¿Qué es Spring?

n  Framework de código abierto creado por Rod Johnson n  http://www.springframework.org

n  Motivación: facilitar el desarrollo de aplicaciones Java EE, promoviendo buenas prácticas de diseño y programación n  Simplifica el uso de muchas de las APIs de Java EE n  Dispone de alternativas a algunas de las APIs de Java EE

n  Internamente se apoyan en APIs de Java EE de más bajo nivel

n  Soporte para capa modelo e interfaz Web n  Es modular: es posible usar algunos de los módulos sin

comprometerse con el uso del resto n  Nosotros utilizaremos fundamentalmente el soporte de Spring para

implementar casos de uso a nivel de capa modelo n  Inyección de dependencias n  Gestión declarativa de transacciones (mediante AOP)

Page 4: Spring en Modelo a Vanz a Do

4 - 4

Módulos/Paquetes (1)

Core IoC Container

AOP Spring AOP

Integración AspectJ

DAO Spring JDBC Transaction

management

ORM Hibernate

JPA JDO

TopLink OJB

iBatis

JEE JMX JMS JCA

Remotig EJBs Email

Web Spring Web MVC

Framework Integration Struts

WebWork Tapestry

JSF Rich View Support

JSPs Velocity

FreeMarker PDF

Jasper Reports Excel

Spring Portlet MVC

Page 5: Spring en Modelo a Vanz a Do

4 - 5

Módulos/Paquetes (2)

n  Core n  Constituye la parte fundamental del framework y

proporciona la característica de Inyección de Dependencias (DI) / Inversión de Control (IoC)

n  DAO n  Proporciona una manera de gestionar transacciones tanto

programática como declarativamente n  También proporciona una capa de abstracción sobre JDBC

que elimina la necesidad de codificar y analizar los códigos de error específicos de cada BBDD

Page 6: Spring en Modelo a Vanz a Do

4 - 6

Módulos/Paquetes (y 3)

n  ORM n  Proporciona capas de integración para las APIs de

mapeadores objeto-relacionales más populares: Hibernate, JPA, JDO, iBatis

n  Utilizando este paquete es posible utilizar cualquiera de estos mapeadores objeto-relacionales en combinación con las demás características que ofrece Spring (como por ejemplo con la gestión declarativa de transacciones)

n  AOP n  Proporciona una implementación del paradigma de la

programación orientada a aspectos (conforme a la AOP Alliance), que es utilizada, transparentemente para el programador, por otros paquetes de Spring, pero que también puede ser usada directamente

Page 7: Spring en Modelo a Vanz a Do

4 - 7

El Contenedor (1)

n  El contenedor de IoC es el núcleo del sistema n  Responsable de la creación y configuración de los Beans n  Nota: Un bean, en el contexto de Spring, es un POJO que es

creado y manejado por el contenedor de IoC

n  La interfaz BeanFactory o sus descendientes ListableBeanFactory y ApplicationContext representan la interfaz del contenedor n  Spring proporciona varias implementaciones

n  E.g. ClassPathXmlApplicationContext

Page 8: Spring en Modelo a Vanz a Do

4 - 8

El Contenedor (2)

n  Instanciación try { ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {SPRING_CONFIG_FILE, SPRING_CONFIG_TEST_FILE}); AccountService accountService = ctx.getBean(AccountService.class); ... } catch (Exception e) { e.printStackTrace(); }

Page 9: Spring en Modelo a Vanz a Do

4 - 9

El Contenedor (y 3)

n  ClassPathXmlApplicationContext n  Permite declarar los objetos que componen la aplicación, y las

dependencias entre ellos en XML n  A partir de los metadatos de configuración en XML es capaz

de crear y configurar los objetos que componen la aplicación n  Tiene métodos que permiten obtener referencias a los objetos

declarados, a partir de su tipo o nombre. Algunos son n  T getBean(Class<T> requiredType)

n  Devuelve un bean del tipo indicado solamente si hay exactamente uno de ese tipo. En otro caso lanza una excepción

n  Object getBean(String name) n  Devuelven el bean que tiene el nombre indicado

n  T getBean(String name, Class<T> requiredType) n  Equivalente al anterior pero además proporciona “type safety” y

lanza una excepción si el bean no es del tipo indicado

Page 10: Spring en Modelo a Vanz a Do

4 - 10

Declaración de Beans en XML (1)

n  Es equivalente a

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/pojo" p:username="pojo" p:password="pojo" />

<bean id="accountService" class="es.udc.pojo.minibank.model.accountservice.AccountServiceImpl" p:accountDao-ref="accountDao" p:accountOperationDao-ref="accountOperationDao" />

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >

<property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost/pojo" /> <property name="username" value="pojo" />

<property name="password" value="pojo" /> </bean>

<bean id="accountService" class="es.udc.pojo.minibank.model.accountservice.AccountServiceImpl" > <property name="accountDao" ref="accountDao" /> <property name="accountOperationDao" ref="accountOperationDao" />

</bean>

Page 11: Spring en Modelo a Vanz a Do

4 - 11

Declaración de Beans en XML (2)

n  Se declaran con la etiqueta bean n  Parámetros básicos

n  id: Nombre o identificador del bean n  class: Clase de implementación del bean

n  Inyección de dependencias basada en “setters” n  Permite inyectar valores u otros beans (a través de

referencias), invocando al método set correspondiente del bean sobre el que se está realizando la inyección

n  Se indica el nombre de la propiedad que se desea inyectar y el valor que se le desea proporcionar

Page 12: Spring en Modelo a Vanz a Do

4 - 12

Declaración de Beans en XML (y 3)

n  Inyección de dependencias basada en “setters” (cont) n  Es posible especificarlas

n  A través de un elemento anidado property, que acepta los siguientes atributos

n  name: Nombre de la propiedad donde se desea inyectar el valor n  value: Para inyectar un valor constante n  ref: Para inyectar otro bean a partir de su nombre

n  Con sintaxis abreviada (utilizando el espacio de nombres p) a través de los atributos

n  p:nombrePropiedad: Para inyectar un valor constante en la propiedad indicada

n  p:nombrePropiedad-ref: Para inyectar otro bean a partir de su nombre en la propiedad indicada

n  El bean se crea a partir de su constructor vacío y a continuación se invocan los métodos set con los valores adecuados

Page 13: Spring en Modelo a Vanz a Do

4 - 13

Declaración de Beans Usando Anotaciones (1)

@Repository("accountDao") public class AccountDaoHibernate extends GenericDaoHibernate<Account, Long> implements AccountDao { ... } @Repository("accountOperationDao") public class AccountOperationDaoHibernate extends GenericDaoHibernate<AccountOperation, Long> implements AccountOperationDao { ... } @Service("accountService") public class AccountServiceImpl implements AccountService { ... }

Page 14: Spring en Modelo a Vanz a Do

4 - 14

Declaración de Beans Usando Anotaciones (2)

n  Spring proporciona un mecanismo para detectar automáticamente clases anotadas y registrarlas como beans en el ApplicationContext n  Se puede utilizar la anotación genérica @Component sobre

cualquier clase, o sus especializaciones @Repository, @Service y @Controller para anotar clases en las capas de persistencia, servicios y vista respectivamente

n  La documentación de Spring aconseja utilizar las especializaciones porque otros frameworks o herramientas pueden aplicarles semántica especial y el propio Spring puede añadírsela en futuras versiones

n  Si la anotación contiene el atributo value, entonces el valor de ese atributo será el que dé nombre al bean; en otro caso, se le dará el mismo nombre que la clase pero empezando por minúscula

n  NOTA: Si una anotación sólo tiene un parámetro y se llama value, no hace falta poner @Anotacion(value="valor"), basta poner @Anotacion("valor")

Page 15: Spring en Modelo a Vanz a Do

4 - 15

Declaración de Beans Usando Anotaciones (y 3)

n  Spring proporciona un mecanismo para detectar automáticamente clases anotadas y registrarlas como beans en el ApplicationContext (cont) n  Además debe utilizarse el tag component-scan en el

fichero de configuración de Spring indicando en el atributo base-package el o los paquetes (separados por comas) que incluyen las clases anotadas (puede ser un paquete padre, no es necesario que sean los paquetes que contienen las clases directamente)

<beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="... "> ... <context:component-scan base-package="es.udc.pojo.minibank.model"/> ... </beans>

Page 16: Spring en Modelo a Vanz a Do

4 - 16

Auto-inyección de Dependencias n  El contenedor de Spring es capaz de auto-inyectar dependencias

entre beans según diferentes criterios n  Por tipo: Busca un bean con el mismo tipo que la propiedad n  Por nombre: Busca un bean con el mismo id que la propiedad n  Por constructor: Busca uno o más beans cuyos tipos coincidan con

los parámetros de uno de los constructores de ese bean n  Cuando se usan metadatos de configuración en XML, la auto-

inyección de dependencias se especifica a través del atributo autowire de la etiqueta <bean/>

n  También es posible realizar auto-inyección de dependencias utilizando la anotación @Autowired n  Ventajas

n  La cantidad de configuración necesaria puede verse reducida significativamente, y también las necesidades de cambios en dicha configuración según avanza el desarrollo

n  Desventajas n  Las relaciones entre los beans dejan de estar documentadas

explícitamente n  Si hay varios beans con el mismo tipo no puede utilizarse la auto-

inyección por tipo (que es la que suele utilizarse)

Page 17: Spring en Modelo a Vanz a Do

4 - 17

Auto-Inyección de Dependencias Usando Anotaciones (1)

@Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired

private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao; ... }

Page 18: Spring en Modelo a Vanz a Do

4 - 18

Auto-Inyección de Dependencias Usando Anotaciones (y 2)

n  La anotación @Autowired puede ser aplicada a setters, pero también a métodos con nombres arbitrarios y múltiples argumentos, a constructores y a propiedades

n  Por defecto la auto-inyección se realiza por tipo y si no hay ningún bean que la satisfaga entonces se produce un error

n  Para poder utilizar esta anotación es necesario especificar la etiqueta annotation-config en el fichero de configuración de Spring

<beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="... "> ... <context:annotation-config/> ... </beans>

Page 19: Spring en Modelo a Vanz a Do

4 - 19

Beans de la capa modelo de MiniBank (pojo-minibank-spring-config.xml)

<?xml version="1.0" encoding="UTF-8"?> <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="..."> <!-- Enable usage of @Autowired. --> <context:annotation-config/> <!-- Enable component scanning for defining beans with annotations. --> <context:component-scan base-package="es.udc.pojo.minibank.model"/>

... <!-- Hibernate Session Factory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" ... /> ... </beans>

Page 20: Spring en Modelo a Vanz a Do

4 - 20

AccountServiceImpl.java @Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao; ... }

Page 21: Spring en Modelo a Vanz a Do

4 - 21

AccountDaoHibernate.java y AccountOperationDaoHibernate.java

@Repository("accountDao") public class AccountDaoHibernate extends GenericDaoHibernate<Account, Long> implements AccountDao { ... } @Repository("accountOperationDao") public class AccountOperationDaoHibernate extends GenericDaoHibernate<AccountOperation, Long> implements AccountOperationDao { ... }

Page 22: Spring en Modelo a Vanz a Do

4 - 22

GenericDaoHibernate.java public class GenericDaoHibernate<E, PK extends Serializable> implements GenericDao<E, PK> {

private SessionFactory sessionFactory;

... @Autowired public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } ... }

Page 23: Spring en Modelo a Vanz a Do

4 - 23

Beans de la capa modelo de MiniBank

n  Declaración: n  Se declaran los siguientes beans de usuario mediante

anotaciones n  Un bean para cada DAO de Hibernate n  Un bean para la implementación del servicio

n  Se declara un bean en XML para la SessionFactory (que usan los DAOs de Hibernate)

n  Inyección de dependencias n  Las dependencias entre los beans se auto-inyectan mediante

anotaciones n  La implementación del servicio usa los DAOs

n  Se inyectan directamente sobre las propiedades privadas que los referencian y por tanto no son necesarios los setters

n  Los DAOs usan la SessionFactory n  Se inyecta en GenericDaoHibernate sobre el setter

correspondiente (el setter es necesario ya que es invocado desde las clases de prueba)

Page 24: Spring en Modelo a Vanz a Do

4 - 24

Beans: Inyección de Dependencias

AccountServiceImpl

-  accountDao : AccountDao -  accountOperationDao : AccountOperationDao

AccountDaoHibernate

-  sessionFactory : SessionFactory

AccountOperationDaoHibernate

-  sessionFactory : SessionFactory

accountDao

accountService

accountOperationDao

sessionFactory

Page 25: Spring en Modelo a Vanz a Do

4 - 25

Ámbito de los Beans

n  El ámbito de un bean se especifica a través del atributo scope de la etiqueta bean o a través de la anotación @Scope (según se use configuración XML o basada en anotaciones)

n  Algunos posibles valores son: n  singleton (valor por defecto)

n  El contenedor usa siempre la misma instancia (ya sea cuando se le pide a través de la API o cuando necesita inyectarlo)

n  prototype n  Indica que el contenedor debe crear una nueva instancia del

bean cada vez que se precise una n  Puede ser necesario, por ejemplo, si el bean tiene estado

n  OJO con los beans de tipo singleton con dependencias con beans de tipo prototype

Page 26: Spring en Modelo a Vanz a Do

4 - 26

Excepciones de Persistencia (1)

n  En JDBC se lanza la excepción java.sql.SQLException cuando se produce cualquier tipo de error en el acceso a los datos n  Problema: Hay que capturarla siempre y analizarla para

saber de qué tipo de error se trata

n  Algunos frameworks (e.g. Hibernate) ofrecen una jerarquía de excepciones más descriptiva (una excepción diferente para cada tipo de error) n  Ventaja: Permite diferenciar entre qué tipos de errores

capturar n  Problema: Son específicas del framework utilizado para

realizar la persistencia de los datos

Page 27: Spring en Modelo a Vanz a Do

4 - 27

Excepciones de Persistencia (y 2)

n  Spring proporciona una jerarquía de excepciones de acceso a datos (heredan de DataAccessException) que resuelve ambos problemas n  Cada excepción representa un error concreto n  No son específicas del framework de persistencia de datos

utilizado, que por tanto se oculta a las capas superiores n  Son excepciones unchecked

n  Spring proporciona mecanismos para realizar la conversión entre las excepciones nativas del framework de persistencia utilizado y la jerarquía propia n  Para que Spring realice automáticamente la conversión, en

clases anotadas con @Repository, es suficiente con declarar el siguiente bean en el fichero de configuración

<bean class= "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

Page 28: Spring en Modelo a Vanz a Do

4 - 28

DataSources

n  Independientemente del framework de persistencia utilizado probablemente se necesitará configurar una referencia a un DataSource

n  Spring proporciona, entre otras, las siguientes opciones para configurar un bean de tipo DataSource n  DataSources definidos directamente sobre un driver JDBC

n  SingleConnectionDataSource n  DriverManagerDataSource

n  DataSources que son localizados vía JNDI n  Cualquier contenedor Java EE puede poner accesible vía JNDI

un DataSource (que normalmente implementará pool de conexiones)

Page 29: Spring en Modelo a Vanz a Do

4 - 29

SingleConnectionDataSource n  Cuando se crea, solicita una conexión a la base de datos n  El método getConnection siempre devuelve esa conexión (o un

proxy) n  Este DataSource sólo es válido para entornos single-thread

n  Es usual especificar suppressClose="true" para que devuelva un proxy de la conexión cuyo método close (el del proxy) no cierra la conexión

n  Un DataSource con estas características es suficiente y eficiente para los tests de integración

n  Suficiente: llega con disponer de una conexión n  Eficiente: la conexión a la base de datos sólo se pide cuando se crea el

DataSource n  Además, hay que indicar también las siguientes propiedades

n  El nombre de la clase del driver JDBC n  La URL de conexión a la BD n  El usuario para conectarse a la BD n  La contraseña del usuario indicado

<bean id="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/pojotest" p:username="pojo" p:password="pojo" p:suppressClose="true" />

Page 30: Spring en Modelo a Vanz a Do

4 - 30

DriverManagerDataSource

n  Implementación simple de la interfaz DataSource n  No implementa pool de conexiones n  El método getConnection devuelve una conexión nueva

cada vez que es invocado n  Válido para entornos multi-thread

n  Un DataSource con estas características es suficientemente eficiente y seguro para probar una aplicación Web a nivel de usuario

n  Hay que indicar las siguientes propiedades n  El nombre de la clase del driver JDBC n  La URL de conexión a la BD n  El usuario para conectarse a la BD n  La contraseña del usuario indicado

n  Es el que usamos con el plugin de Jetty para Maven (src/main/jetty/jetty-env.xml)

Page 31: Spring en Modelo a Vanz a Do

4 - 31

Acceso a DataSources mediante JNDI (1)

n  JNDI (Java Naming and Directory Interface) n  Familia de paquetes javax.naming (Java SE) n  Es una API que abstrae el acceso a un servicio de nombres y

directorios (e.g. LDAP) n  Es posible registrar objetos mediante un nombre jerárquico

n  Los servidores de aplicaciones Java EE exponen diversos objetos mediante JNDI

n  Los servidores de aplicaciones Java EE proporcionan implementaciones de DataSource n  Cada objeto DataSource es accesible a partir de un nombre JNDI

de la forma java:comp/env/XXX/YYY, donde XXX suele (recomendado) ser jdbc e YYY el nombre de un DataSource concreto

n  Habitualmente estos objetos DataSource implementan la estrategia de pool de conexiones

n  Requiere configuración en el servidor (driver, URL, usuario, contraseña, parámetros específicos al pool, etc.)

n  Ej.: En Tomcat se definen en conf/server.xml

Page 32: Spring en Modelo a Vanz a Do

4 - 32

Acceso a DataSources mediante JNDI (y 2)

n  El atributo jndiName se utiliza para indicar el nombre del recurso accesible vía JNDI

n  Si la aplicación está ejecutándose dentro de un servidor de aplicaciones Java EE n  El valor del atributo resourceRef debe ser true n  El nombre indicado en jndiName es relativo al contexto

java:comp/env/ n  JndiObjectFactoryBean implementa

org.springframework.beans.factory.FactoryBean n  Los beans que implementan esta interfaz se definen igual que el

resto de beans, pero cuando se referencian desde otros beans no se inyecta una instancia de ese tipo sino el objeto que devuelve su método getObject

n  El método getObject de JndiObjectFactoryBean devuelve el objeto asociado al nombre JNDI especificado en la configuración

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName="jdbc/pojo-examples-ds" p:resourceRef="true" />

Page 33: Spring en Modelo a Vanz a Do

4 - 33

Integración con Hibernate 4 (1)

n  Los DAOs implementados con Hibernate necesitan un objeto de tipo org.hibernate.SessionFactory del que obtener la sesión actual n  Como veremos más adelante, el gestor de transacciones de

Hibernate también precisa un objeto de ese tipo n  La siguiente declaración permite definir un bean para obtener

un SessionFactory que utiliza las anotaciones de Hibernate en las entidades

n  datasource: indica el nombre de un bean de tipo DataSource (para obtener las conexiones a la BD)

n  configLocation: Indica donde está el fichero de configuración de Hibernate (fichero llamado pojo-minibank-hibernate-config.xml localizado en el classpath de ejecución)

n  LocalSessionFactoryBean es un FactoryBean (igual que la clase JndiObjectFactoryBean explicada en la transparencia anterior) cuyo método getObject devuelve una instancia que implementa SessionFactory

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="dataSource" p:configLocation="classpath:/pojo-minibank-hibernate-config.xml"/>

Page 34: Spring en Modelo a Vanz a Do

4 - 34

Integración con Hibernate 4 (2)

n  Como ya hemos visto con anterioridad el bean sessionFactory se inyecta en el DAO genérico

public class GenericDaoHibernate<E, PK extends Serializable> implements GenericDao<E, PK> {

private SessionFactory sessionFactory;

... @Autowired public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } ... }

Page 35: Spring en Modelo a Vanz a Do

4 - 35

Integración con Hibernate 4 (3)

n  Fichero de configuración de Hibernate: pojo-minibank-hibernate-config.xml

<hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.use_sql_comments">true</property> <mapping class="es.udc.pojo.minibank.model.account.Account" /> <mapping class="es.udc.pojo.minibank.model.accountoperation.AccountOperation" /> </session-factory> </hibernate-configuration>

Page 36: Spring en Modelo a Vanz a Do

4 - 36

Integración con Hibernate 4 (y 4)

n  Fichero de configuración de Hibernate: pojo-minibank-hibernate-config.xml (cont) n  No contiene la configuración de la BD/pool porque al SessionFactory inyectado por Spring en el DAO genérico ya se le ha inyectado un DataSource

n  Cuando se ejecuta la aplicación en un servidor de aplicaciones, se utiliza el DataSource (accesible vía JNDI) proporcionado por el servidor de aplicaciones

n  Cuando se ejecutan las pruebas se utiliza un DataSource de tipo SingleConnectionDataSource declarado en el fichero de configuración de Spring para pruebas (pojo-minibank-spring-config-test.xml) que sobrescribe al anterior

n  No se utiliza la siguiente propiedad porque el SessionFactory inyectado por Spring en el DAO genérico ya implementa esa semántica

<property name="current_session_context_class">thread</property>

Page 37: Spring en Modelo a Vanz a Do

4 - 37

Transacciones

n  Spring no gestiona directamente las transacciones, sino que lo hace a través de una abstracción (patrón Strategy) n  Interfaz

org.springframework.transaction.PlatformTransactionManager

n  Se puede trabajar con las transacciones independientemente de la implementación del gestor de transacciones concreto que se esté utilizando

n  Spring proporciona una serie de gestores de transacciones que delegan la responsabilidad de la gestión de las transacciones a implementaciones específicas de la plataforma utilizada

n  Se puede trabajar con transacciones a través de la API Java de Spring, pero también se pueden definir de forma declarativa haciendo uso del framework AOP de Spring, que incluye una implementación del aspecto de transaccionalidad n  Es posible hacerlo mediante XML o mediante anotaciones Java n  Utilizaremos la opción de las anotaciones porque simplifica la

declaración de las transacciones

Page 38: Spring en Modelo a Vanz a Do

4 - 38

Transacciones con Hibernate 4

n  Si la capa de persistencia del modelo está implementada con Hibernate, entonces el gestor de transacciones a utilizar es el siguiente

n  Es preciso inyectarle un objeto SessionFactory de Hibernate n  Ya hemos declarado uno para utilizar en los DAOs

n  HibernateTransactionManager delega la gestión de las transacciones a un objeto org.hibernate.Transaction n  A partir del objeto SessionFactory obtiene la sesión Hibernate n  A partir de la sesión Hibernate obtiene el objeto Transaction

<bean id="transactionManager“

class="org.springframework.orm.hibernate4.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />

Page 39: Spring en Modelo a Vanz a Do

4 - 39

API Transacciones (1) public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }

Page 40: Spring en Modelo a Vanz a Do

4 - 40

API Transacciones (y 2)

n  Un gestor de transacciones implementa la interfaz PlatformTransactionManager n  TransactionException es una excepción unchecked n  El método getTransaction devuelve un objeto de tipo TransactionStatus en función de un parámetro de tipo TransactionDefinition

n  TransactionStatus es una interfaz que representa una transacción

n  Puede ser la transacción actual o una nueva n  TransactionDefinition es una interfaz a través de la cual

se pueden especificar las características de la transacción que se quiere obtener (propagación, nivel de aislamiento, timeout, propiedad read-only)

n  Si se pasa null en getTransaction, se utilizan los valores por defecto

n  Los métodos commit y rollback se utilizan para hacer un commit o un rollback de la transacción que se les pasa

Page 41: Spring en Modelo a Vanz a Do

4 - 41

AOP: Gestión de Transacciones (1)

@Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private PlatformTransactionManager transactionManager; @Autowired private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao;

Page 42: Spring en Modelo a Vanz a Do

4 - 42

AOP: Gestión de Transacciones (2) public Account createAccount(Account account) {

TransactionStatus transactionStatus = transactionManager.getTransaction(null);

try {

accountDao.save(account);

transactionManager.commit(transactionStatus); } catch (RuntimeException|Error e) { transactionManager.rollback(transactionStatus);

throw e; }

return account;

}

Iniciar transacción

Finalizar transacción

Page 43: Spring en Modelo a Vanz a Do

4 - 43

AOP: Gestión de Transacciones (3) public void removeAccount(Long accountId) throws InstanceNotFoundException { TransactionStatus transactionStatus = transactionManager.getTransaction(null);

try { accountDao.remove(accountId); accountOperationDao.removeByAccountId(accountId);

transactionManager.commit(transactionStatus); } catch (RuntimeException|Error e) { transactionManager.rollback(transactionStatus);

throw e; } catch (InstanceNotFoundException e) {

transactionManager.commit(transactionStatus); throw e; }

}

Iniciar transacción

Finalizar transacción

Page 44: Spring en Modelo a Vanz a Do

4 - 44

AOP: Gestión de Transacciones (4) public void withdrawFromAccount(Long accountId, double amount) throws InstanceNotFoundException, InsufficientBalanceException { TransactionStatus transactionStatus = transactionManager.getTransaction(null);

try {

/* Find account. */ Account account = accountDao.find(accountId);

/* Modify balance. */ double currentBalance = account.getBalance();

if (currentBalance < amount) { throw new InsufficientBalanceException(accountId,

currentBalance,amount); }

account.setBalance(currentBalance - amount);

Iniciar transacción

Page 45: Spring en Modelo a Vanz a Do

4 - 45

AOP: Gestión de Transacciones (5)

/* Register account operation. */ accountOperationDao.save(new AccountOperation(account, Calendar.getInstance(), AccountOperation.Type.WITHDRAW,

amount));

transactionManager.commit(transactionStatus); } catch (RuntimeException|Error e) { transactionManager.rollback(transactionStatus); throw e; } catch (InstanceNotFoundException| InsufficientBalanceException e) {

transactionManager.commit(transactionStatus); throw e; }

} ... }

Finalizar transacción

Page 46: Spring en Modelo a Vanz a Do

4 - 46

AOP: Gestión de Transacciones (6)

n  El código para todos los casos de uso transaccionales es similar: n  Iniciar la transacción (con las propiedades adecuadas) a

partir del gestor de transacciones utilizado n  Ejecutar la lógica propia del caso de uso n  Finalizar transacción (commit o rollback) en función de si se

ha producido alguna excepción o no y de su tipo

n  El código común para la gestión de las transacciones puede eliminarse de la implementación de todos los casos de uso que lo precisen, y declarativamente decir cuándo debe ejecutarse

Page 47: Spring en Modelo a Vanz a Do

4 - 47

AOP: Gestión de Transacciones (y 7)

n  Declarativamente es posible indicar n  El gestor de transacciones a utilizar n  Que los métodos createAccount, removeAccount, withdrawFromAccount y todos los demás de la clase AccountServiceImpl son transaccionales

n  Spring intercepta las invocaciones a los métodos declarados como transaccionales:

n  [Antes de que se ejecute el método] Ejecuta el código necesario para comenzar la transacción

n  Declarativamente pueden indicarse parámetros como, por ejemplo, el nivel de aislamiento deseado para la transacción

n  [Después de que se ejecute el método] Ejecuta el código necesario para finalizar la transacción (ya sea con un commit o un rollback)

n  Pueden indicarse qué excepciones deben provocar un rollback y cuales no

Page 48: Spring en Modelo a Vanz a Do

4 - 48

AccountServiceImpl.java (1) @Service("accountService") @Transactional public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao; public Account createAccount(Account account) { ... }

@Transactional(readOnly = true) public Account findAccount(Long accountId)

throws InstanceNotFoundException { ... }

public void addToAccount(Long accountId, double amount) throws InstanceNotFoundException { ... }

Page 49: Spring en Modelo a Vanz a Do

4 - 49

AccountServiceImpl.java (2) public void withdrawFromAccount(Long accountId, double amount) throws InstanceNotFoundException, InsufficientBalanceException { /* Find account. */ Account account = accountDao.find(accountId); /* Modify balance. */ double currentBalance = account.getBalance(); if (currentBalance < amount) { throw new InsufficientBalanceException(accountId, currentBalance,amount); } account.setBalance(currentBalance - amount); /* Register account operation. */ accountOperationDao.save(new AccountOperation(account, Calendar.getInstance(), AccountOperation.Type.WITHDRAW, amount)); }

Page 50: Spring en Modelo a Vanz a Do

4 - 50

AccountServiceImpl.java (3) @Transactional(readOnly = true) public AccountBlock findAccountsByUserId(Long userId, int startIndex, int count) { ... } public void removeAccount(Long accountId) throws InstanceNotFoundException { ... }

public void transfer(Long sourceAccountId, Long destinationAccountId, double amount) throws InstanceNotFoundException, InsufficientBalanceException { ... }

@Transactional(readOnly = true) public int getNumberOfAccountOperations(Long accountId, Calendar startDate, Calendar endDate) throws InstanceNotFoundException { ... } @Transactional(readOnly = true) public List<AccountOperation> findAccountOperationsByDate( Long accountId, Calendar startDate, Calendar endDate, int startIndex, int count) throws InstanceNotFoundException { ... } }

Page 51: Spring en Modelo a Vanz a Do

4 - 51

Transacciones con Anotaciones

n  Si se desean utilizar anotaciones para declarar las transacciones, el gestor de transacciones a utilizar se declara a través de la etiqueta annotation-driven, perteneciente al espacio de nombres tx

n  El valor del atributo transaction-manager indica el nombre del bean que debe ser utilizado como gestor de transacciones n  Este atributo es opcional, y si no está presente toma el valor

por defecto “transactionManager” n  Por tanto en nuestro caso podríamos no haberlo

especificado

<tx:annotation-driven transaction-manager="transactionManager" />

Page 52: Spring en Modelo a Vanz a Do

4 - 52

Anotación @Transactional (1)

n  Puede utilizarse para anotar una clase o un método concreto n  En una clase se aplica a todos los métodos que contiene n  En un método sobrescribe el comportamiento especificado

para la clase a la que pertenece n  Propiedades:

n  propagation: n  Permite especificar la semántica de la creación de la

transacción n  El enumerado org.springframework.transaction.annotation.Propagation define diversos valores

n  Por defecto toma el valor Propagation.REQUIRED: el método debe ejecutarse dentro de una transacción; si ya existe una, se ejecuta en esa, y si no, se crea una nueva

Page 53: Spring en Modelo a Vanz a Do

4 - 53

Anotación @Transactional (2)

n  Propiedades (cont.): n  isolation: Nivel de aislamiento

n  Isolation.DEFAULT (valor por defecto): El de la plataforma n  Isolation.READ_UNCOMMITED: Pueden ocurrir “dirty

reads”, “non-repeatable reads” y “phanton reads” n  Isolation.READ_COMMITED: Pueden ocurrir “non-

repeatable reads” y “phamton reads” n  Isolation.REPETEABLE_READ: Pueden ocurrir “phanton

reads” n  Isolation.SERIALIZABLE: Elimina todos los problemas de

concurrencia n  readOnly: Lectura/escritura (defecto) o solo lectura

n  Importante indicarlo para poder hacer optimizaciones !! n  timeout: Timeout de la transacción (por defecto el de la

plataforma) n  Si el timeout expira entonces se hace un rollback de la

transacción

Page 54: Spring en Modelo a Vanz a Do

4 - 54

Anotación @Transactional (y 3)

n  Por defecto cualquier excepción de tipo “unchecked” (hija de RuntimeException) provocará un rollback, y cualquier excepción “checked” (hija de Exception) no n  Es posible modificar este comportamiento a través de propiedades

de la anotación @Transactional n  rollbackFor: array de excepciones que deben causar un rollback

n  Ejemplo:

n  noRollbackFor: array de excepciones que no deben causar un rollback

n  La utilizaremos en los servicios del modelo para declarar la transaccionalidad de sus métodos n  Es posible anotar la interfaz que declara las operaciones del

servicio, pero es más recomendable anotar la clase de implementación del servicio

@Transactional(rollbackFor={Exception1.class, Exception2.class})

Page 55: Spring en Modelo a Vanz a Do

4 - 55

Invocación de casos de uso n  Clase WithdrawFromAccount n  Paquete

es.udc.pojo.minibank.test.experiments.spring n  Ilustra cómo obtener una referencia a un servicio implementado

con Spring y llamar a un caso de uso ... try { /* Get service object. */ ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {SPRING_CONFIG_FILE, SPRING_CONFIG_TEST_FILE}); AccountService accountService = ctx.getBean(AccountService.class); accountService.withdrawFromAccount(accountId, amount); } catch (InstanceNotFoundException e) { e.printStackTrace(); } catch (InsufficientBalanceException e) { e.printStackTrace(); } ...

Page 56: Spring en Modelo a Vanz a Do

4 - 56

Implementación de Servicios (1)

n  Los casos de uso se implementan en términos de DAOs (tal como se vio en el tema 2) n  En los DAOs se inyecta un objeto de tipo org.hibernate.SessionFactory creado por Spring (al que a su vez se le inyecta un DataSource)

n  Los DAOs se inyectan en la clase de implementación del Servicio

n  Se utiliza un mecanismo proporcionado por Spring para convertir las excepciones de persistencia nativas a una jerarquía propia, independiente del framework utilizado para la persistencia

Page 57: Spring en Modelo a Vanz a Do

4 - 57

Implementación de Servicios (y 2)

n  Para indicar la transaccionalidad de los casos de uso utilizamos la anotación @Transactional sobre la clase de implementación del Servicio n  Se declara un gestor de transacciones que delega en el

gestor de transacciones de Hibernate n  Se le inyecta el mismo SessionFactory que el creado para

inyectar en los DAOs, para que pueda acceder a través de él al gestor de transacciones de Hibernate

n  La implementación de los Servicios es independiente del software utilizado para el acceso a datos (en nuestro caso Hibernate)