Spring framework

159

Transcript of Spring framework

Page 1: Spring framework
Page 2: Spring framework

Spring es un framework ligero para el desarrollo de aplicaciones.

Strtus, WebWork y otros son frameworks paraweb. Spring, por contra, da soporte a todaslas capas de una aplicación.

Nos evita “la fontanería” que normalmente el desarrollador se ve obligado a implementar a mano.

Page 4: Spring framework

Spring no es un servidor de aplicaciones JEE, sino que se integra en las aplicaciones que se despliegan sobre ellos, y sobre aplicacionesJava en general.

Spring sustituye ¿elegantemente? algunos de los servicios que aportan los servidores de aplicaciones JEE.

Page 5: Spring framework

Spring propone una estructura consistente paratoda la aplicación

Facilita un método consistente para pegar todoslos elementos de la aplicación.

Abierto a la integración con múltiples estándares e implementaciones populares como: Hibernate, JDO, TopLink, EJB, RMI, JNDI, JMS, Web Services, Struts, etc.

Permite aumentar nuestra productividad evitándoal desarrollador la tarea de implementar tareasderivadas de la integración de los componentes de la aplicación.

Page 6: Spring framework

From springframework.org

Los creadores de Spring defienden que: JEE debería ser más sencilla de usar Es preferible programar interfaces a programar

clases, pero ésto conlleva usualmente un costeadicional de implementación. Spring lo facilitareduciendo la implementación desacopladabasándose en interfaces.

La especificación de JavaBeans ofrece ciertasventajas a la hora de externalizar y modularizar la configuración de las aplicaciones.

El paradigma OO debe imponerse sobre la tecnología subyacente como _JEE

Page 7: Spring framework

Filosofía POJO, menos interfaces y excepcioneschequeadas que fuerzan a complicar el códigocuando integramos elementos diferentes.

La prueba del software son esenciales. Spring nosayuda a implementar código chequeable mediantepruebas unitarias.

La aplicación de Spring debe ser placentera.

El código de la aplicación no debe depender de lasAPIs de Spring.

Spring no debe competir con soluciones que yafuncionan, sino permitir su fácil integración en la aplicación (Ej, Hibernate, JDO, etc.)

Page 8: Spring framework

from springframework.org

Page 9: Spring framework

¿Qué implica esto? No fuerza a importar o extender ninguna API de

Spring. Una tecnología invasiva compromete nuestro

código con sus implementaciones- Anti-patrones:

◦ EJB nos fuerza a usar JNDI◦ Struts 1.x fuerza a extender la clase Action

Los Frameworks invasivos son por lo general difícilesde testear.

Page 10: Spring framework

Fundamentalmente, Spring se compone de:

Contenedor de inversión de control (IoC)◦ Aplicación de la técnica de inyección de dependencias

(Fowler)

Un framework AOP.◦ Spring facilita un framework AOP basado en proxy.◦ Integrable con AspectJ o AspectWerkz

Una capa de abstracción de servicios◦ Integración consistente con varios estándares y APIs

populares.

Todo ello está basado en la implementación de aplicaciones usando POJOs.

Page 11: Spring framework
Page 12: Spring framework

Gestiona objetos como componentes, permitiendo:◦ Crearlos

◦ Configurarlos

◦ “Cablearlos” (Wiring) – Enlazado entre objetos.

◦ Controlar todo si ciclo de vida

◦ Controlar su destrucción

Ofrece varios tipos de contenedor diferentes, clasificables en dos tipos:◦ BeanFactory

◦ ApplicationContext (más completo)

Page 13: Spring framework

Descarguemos el piloto 1.0 y analicemos su código.

¿Funciona?

¿Cómo están las clases?

¿Con cuantos tipos de actores puede funcionar el espectáculo que estamos modelando?

¿Qué tengo que hacer para variar el tipo de actor?

Page 14: Spring framework

Bajamos ahora el piloto 2.0.

¿Qué hemos mejorado?

¿Están las clases completamente desacopladas por el mero hecho de utilizar una interfaz?

Taller prácticoCompletar el modelo para que incorpore la clase

es.uniovi.si.factoria.Factoria que:

• haga de factoría

• sea un singleton

• tenga un método Object getService(String) que cuando reciba “Malabarista” devuelva una instancia de la clase Malabarista.

(Resuelto en piloto 3.0)

Page 15: Spring framework

El BeanFactory es una implementación del patrón factoría que permite crear beans declarándolos en un ficheros XML cuyaraiz es la etiqueta <beans>

El XML contiene uno o más elementos de tipo <bean>◦ Atributo id (o nombre) para identificar el bean◦ Atributo class que especifica el nombre

cualificado completo de la clase queimplementará el bean bautizado con id

Page 16: Spring framework

Por defecto, los beans son tratados comosingletons (Dessign patterns, GoF’94),aunque existen otros posibles patrones de comportamiento.

Ejemplo:

<beans>

<bean id=“widgetService”

class=“com.zabada.base.WidgetService”>

</bean>

</beans>

The bean’s IDThe bean’s fully-

qualified classname

Page 17: Spring framework

Para utilizarlo:BeanFactory factory = new XmlBeanFactory(<documento xml>);

Factory.getBean(<identificador del bean>);

El documento XML debe ser encapsulado por alguna de las

siguientes clases wrapper.Implementación Propósito

ByteArrayResource El documento viene como un array de bytes

ClassPathResource Busca el documento en el classpath

DescriptiveResource Mantiene una descripción del documento pero no el fichero de recursos en sí.

FileSystemResource Carga el documento del sistema de ficheros

InputStreamResource Carga el documento como un inputStream

PortletContextResource Lo busca en el contexto de portlets

ServletContextResource Lo busca en el contexto de los servlets

UrlResource Lo descarga de una url concreta

Page 18: Spring framework

El documento XML declara los beans, asociándoles el identificador por el cual van a ser referenciados.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="actor"

class="es.uniovi.si.Malabarista"/>

</beans>

Page 19: Spring framework

Descargar piloto 4.0 y examinar el código fuente.

Extender ésta versión del piloto para que la clase Show:◦ Implemente un interfaz evento que contenga su

método de comienzo.

◦ Sea también creada por medio de la factoría BeanFactory, bajo el id de evento.

(Resuelto en piloto 5.0)

Page 20: Spring framework
Page 21: Spring framework

Etapa Descripción

Instantiate. Instancia el Bean

Populate properties. Spring Inyecta las propiedades.

Set Bean name Si el bean implementa BeanNameAware, Spring le facilita su id invocando setBeanName.

Set Bean Factory Si el bean implementa BeanFactoryAware, Spring le facilita su factoría invocando setFactory.

Postprocess (antes de la inicialización)

Si existen BeanPostProcessors, Spring invoca su método postProcessBeforeInitialization()

Intialize beans Si implementa InitializingBean, invoca afterPropertiesSet()

PostProcess Si existen BeanPostProcessors, Spring invoca su

método postProcessAfterInitialization()

Bean Ready to Use El bean pasa a estar disponible.

Destroy Bean Si implementa DisposableBean, se invoca su método destroy()

Page 22: Spring framework

A partir del piloto 5.0, ◦ Definir un constructor público en la clase

Malabarista que inicialice el número de objetos con los que hace los malabarismos.

◦ Modificar el bean.xml para que reciba 15 como parámetro de constructor al crear el bean.

◦ Probarlo◦ Una vez comprobado, sobrecargamos el constructor

con otro que reciba una cadena de texto y la muestre por pantalla. ¿Qué sucede?

◦ Añadir la etiqueta type para forzar a que se dispare el constructor que nos interesa.

(resuelto en piloto 6.0)

Page 23: Spring framework

Es el segundo tipo de inyección de dependencias posible.

En lugar de pasarle la información por medio del método constructor, le decimos a Spring que le haga llegar la propiedad en el bean.xml

Para ello debemos:◦ Tener un método set para la propiedad

◦ Añadir una etiqueta property anidada a la definición del bean en el bean.xml

<property name ="numeroObjetos" value="15"/>

Page 24: Spring framework

Además de valores sencillos, es posible inyectar una referencia a otro bean dado de alta en el contenedor.

Ejemplo:<bean name=“widgetService” class=“com.zabada.base.

WidgetServiceImpl”>

<property name=“widgetDAO”>

<ref bean=“myWidgetDAO”/>

</property>

</bean>

Esto implica que la clase WidgetServiceImpldeberá tener un métodosetWidgetDAO(WidgetServiceImpl ref)

Page 25: Spring framework

Modificar el piloto para que la clase Show reciba como dependencia la instancia de la clases Malabarista en su propiedad actor.

(Resuelto en piloto 7.0)

Page 26: Spring framework

Es una extensión del BeanFactory (hereda de él)

Permite más opciones:◦ Incorpora mecanismos para la externalización de

cadenas de texto e internacionalización (i18n)

◦ Unifica la carga de recursos, como las imágenes.

◦ Permite implementar un modelo de paso de mensajes mediante eventos a los beans, declarándolos como listeners del evento.

Por lo general, se usa éste en lugar del BeanFactory, a no ser que estemos en entornos de recursos restringidos (dispositivos móviles o similares).

Page 27: Spring framework

Hay tres implementaciones del contenedor:

Ejemplo:ApplicationContext context = new

FileSystemXmlApplicationContext("c:/foo.xml");

Tipo Descripción

ClassPathXmlApplicationContext Carga el documento XMLbuscándolo en el classpath

FileSystemXmlApplicationContext Lo busca en el sistema de ficheros

XmlWebApplicationContext Lo busca como doc. XML contenido en una aplicación web.

Page 28: Spring framework
Page 29: Spring framework

Descargar la versión 8.0 del piloto y examinar el código fuente.

Ejecutarlo para comprobar que funciona correctamente.

Page 30: Spring framework

Vamos a extender el piloto 8.0 de forma que:◦ Aparezca una interfaz Instrumento con el método toca()

que devuelve un String.◦ Aparezca una clase Saxofon que implemente la interfaz

Instrumento y suene “tuuuut tuuuuu tutuuuu utuuuu”◦ Aparezca un nuevo actor de tipo Instrumentista tal que: Reciba por setter: Nombre El instrumento que toca

Al actuar, muestre un mensaje diciendo que “fulanito hace …” con el sonido que haga el instrumento que esté tocando

◦ Damos de alta un nuevo bean kenny, que se llame Kenny G , que toque el saxofón y hacemos que sea él el que actúe en el Show.

Resuelto en piloto 9.0

Page 31: Spring framework

Supuesto:◦ Contratamos a otro saxofonista para el Show:

<bean id="kenny"

class="com.springinaction.springidol.Instrumentalist">

<property name=“nombre“ value=“juan”/>

<property name="instrument">

<ref bean="saxofon"/>

</property>

</bean>

Pero…:◦ A Kenny G (que “ye” muy fino) no le gusta compartir

el saxofón¿Cuántas instancias se crean del instrumento?

Page 32: Spring framework

Inspirados en las inner classes de Java (Clases que de definen dentro de otras clases)

Los inner beans son beans que se definen dentro de otros beans, y cuyo ámbito se reduce al bean contenedor.

El bean contenido sólo será accesible por el que lo contiene:

<property name="instrument">

<bean class="org.springinaction.springidol.Saxophone" />

</property>

(Ver ejemplo en piloto 10.0)

Page 33: Spring framework

Hasta ahora hemos visto como utilizar Spring para configurar propiedades simples, de un solo valor o referencia. Pero… ¿Cómo hacerlo cuando tratamos con colecciones?

Spring permite trabajar con cuatro tipos de colecciones.

Colección Descripción

List Lista de elementos con duplicados permitidos

Set Conjunto (sin elementos repetidos)

Map Colección de pares nombre-valor donde ambos elementos pueden ser de cualquier tipo

Props Colección de pares nombre-valor donde ambos elementos son de tipo String

Page 34: Spring framework

Si quisiéramos que en Show participasen kenny y el bean actor.◦ Modificaremos la clase Show para que: En lugar de tener un atributo de tipo actor, lo tenga de tipo

Collection<Actor>, con su correspondiente método setActores(…)

Al comenzar el show, haga actuar a todos los actores del espectáculo que encuentre en la colección.for ( Actor actor:actores ){

actor.actua();

}

◦ Extendemos el beans.xml para anidar a los dos actores<property name="actores">

<list>

<ref bean…/>

</list>

Resuelto en piloto 11.0

Page 35: Spring framework

A partir del piloto 10, completarlo para que entre el malabarista y el saxofonista, actúe un hombre orquesta que toque el saxofón, la armónica y la guitarra. La armónica es suya y no la comparte, pero la guitarra es de la organización del show.

Usaremos por convenio los nombres:◦ Clase Guitarra.◦ Clase Armonica◦ Clase HombreOrquesta◦ Clase ◦ Hombre orquesta: Benja

(Resuelto en piloto 11.0)

Page 36: Spring framework

Para “cablear” un Map,◦ El objeto se tiene que esperar que le pasen como

parámetro una instancia de la clase Map.

Public void setInstrumentos(Map

<String,Instrumento>)…

◦ El beans.xml debe enlazar el mapa con el parámetro instrumentos.

<map>

<entry key="la guitarra" value-ref="fender" />

Page 37: Spring framework

Extender piloto 11.0 para que en lugar de pasar directamente las referencias a los beans que toca el Hombre Orquesta, le pasemos un mapa con el nombre que le queramos dar al instrumento, de forma que el mensaje al tocarlo sea…

“El hombre orquesta toca la guitarra: rrriaaannn riiiaaaannn riiiiaaaannnnnnnn”

Resuelto en piloto 12

Page 38: Spring framework

Modificar el piloto 12 para que:◦ A cada actor pueda asignársele un nombre artístico cada

vez que se enlace al show◦ La salida una vez resuelto, será algo como:

Presentamos a Tony Malabares

Haciendo malabarismos con 15 objetos

Presentamos a El Increible hombre orquesta

El hombre orquesta toca la guitarra:rrriaaannnriiiaaaannn riiiiaaaannnnnnnn

El hombre orquesta toca la armónica:tui tui tuiiiiii tuiiiiiii

Presentamos a Kenny G!

Kenny G hace ttuuuuuu tuuuu tuuuuut utuuuuuuuu

Resuelto en piloto 13

Page 39: Spring framework

Hemos visto como “cablear” beans◦ Con el elemento <constructor-arg>◦ Con el elemento <property>

Problema: En una aplicación complicada, esta práctica puede degenerar en un XML desmesurado e inmanejable.

Alternativa: En lugar de definir explícitamente las relaciones entre beans, podemos dejar que Spring decida como debe cablearlos, mediante la propiedad autowire del elemento <bean>

Page 40: Spring framework

Tipos de autocableado:Tipo Descripción

byName Trata de buscar un bean declarado en el contenedor cuyo nombre –o identificador- coincida con la propiedad del bean marcado como autocableable

byType Busca un único bean que coincida en tipo con la propiedad del bean marcado como autocableable. Si no se encuentra, la propiedad se queda sin mapear. Si se encuentra más de una, salta una excepción UnsatisfiedDependencyException

constructor Trata de encajar uno o más beans declarados en el contenedor con los parámetros de alguno de los constructores del bean.

autodetect Trata de aplicar el autowire por constructor, y en caso de no poder, aplica byType. En caso de ambiegüedad, salta una excepción.

Page 41: Spring framework

Todo en Spring tiene un nombre.<bean id="kenny" class="es.uniovi.si.Instrumentista">

<property name="nombre" value="Kenny G"/>

<property name="instrumento">

<bean class="es.uniovi.si.Saxofon"/>

</property>

</bean>

Si queremos simplificar el XML:<bean id=“instrumento” class="es.uniovi.si.Saxofon"/>

…<bean id="kenny" class="es.uniovi.si.Instrumentista“ autowire=“byName”>

<property name="nombre" value="Kenny G"/>

</bean>

Lo cambiamos y lo probamos. ¿Funciona?(Resuelto en piloto 14.0)

Page 42: Spring framework

Similar a byName, salvo que la búsqueda la realiza por tipo, y no por nombre

Por cada bean autocableado por tipo,◦ Introspecciona las propiedades del bean

◦ Por cada setXXX no cableado explícitamente en el beans.xml, busca un bean declarado que coincida en tipo con la propiedad, y si lo encuentra, lo cablea.

Probamos: Partiendo del piloto 14.0, cambiar el autowire a byType. ¿Funciona?

¿Qué podemos hacer para arreglarlo?

(Resuelto en piloto 15.0)

Page 43: Spring framework

Útil cuando utilizamos inyección de dependencias en el constructor.

Si declaramos un bean autocableable por constructor:◦ Spring busca por instrospección los constructores

del bean◦ Por cada uno, trata de buscar candidatos para

satisfacer los tipos de sus parámetros entre los beans declarados en el beans.xml

◦ Si los encuentra, invoca el constructor.

En caso de ambigüedad, dispara una excepción igual que cuando usamos byType

Page 44: Spring framework

Nos permite delegar en el contenedor la decisión de qué bean debe ser cableado con otro, y de qué forma.

<bean id="duke"

class="com.springinaction.springidol.PoeticJuggler"

autowire="autodetect" />

Para este ejemplo, Spring tratará de autocablear el bean por constructor, y en caso de no tener éxito, lo intentará por tipo.

Page 45: Spring framework

Si vamos a adoptar una política común de autocableado para todos los beans, podemos declararla a nivel de contenedor:

<beans default-autowire="byName">

</beans>

Esta propiedad se puede sobrescribir a nivel de bean individual.

Page 46: Spring framework

Hasta ahora hemos usado la creación básica de beans, asumiendo que Spring crea una única instancia de cada uno.

Existen más opciones para gestionar la instanciación de beans:◦ Control del número de instancias creadas

Singleton

Una por request

Una por petición

◦ Creación mediante factoría

◦ Incialización y destrucción controlada del bean

Page 47: Spring framework

Por defecto, todos son singleton

Problema: en determinados contextos, no podemos/queremos usar singletons.

Utilizando el atributo scope del elemento bean determinamos su ciclo de vida:

Scope Descripción

singleton Valor por defecto. Única instancia por contenedor ¿?

prototype Se crea una instancia por petición

request El ámbito se reduce a la request HTTP (Spring MVC)

session El ámbito se reduce a la sesión HTTP (Spring MVC)

global-session El ámbito se reduce al contexto HTTP (Portlets)

Page 48: Spring framework

Si queremos definir un bean como prototype:

<bean id=<identificador>

class=<nombre de la clase>

scope={prototype

|singleton

|request

|session

|global-session/>

Page 49: Spring framework

Modificar la versión 15 del piloto para que:◦ El bean instrumento se instancie una vez por cada

bean que lo utilice

◦ El Hombre Orquesta lo añada a su colección de instrumentos

◦ Junto con el “sonido” del saxofón, se muestre el valor de la referencia del objeto que lo identifica unívocamente en la JVM.

◦ Si ahora quitamos el scope… ¿Hay diferencia?

(Resuelto en piloto 16.0)

Page 50: Spring framework

Normalmente creamos las clases con su constructor público, pero por distintos motivos (código heredad, librerías de terceras partes, etc.), es posible que el bean que queremos “cablear” deba ser creado a partir de un factory method

Ejemplo: ◦ Queremos incorporar a modelo del Show un

escenario que tenemos ya implementado de otra parte del sistema. Como es único, viene implementado como singlenton.

Page 51: Spring framework

Para la instanciación de este tipo de objetos, el elemento bean permite especificar el factory-method que debe invocar el contenedor para obtener una instancia del bean.

<bean id=“<identificador>"

class=“<nombre de la clase>"

factory-method=“<método que retorna la

instancia>" />

Page 52: Spring framework

A partir del piloto 16.0:◦ Crear una clase Escenario que implemente el patrón

singleton, y llamamos al método de creación de instancia getInstancia().

◦ Sobrescribir su método toString para que retorne “Escenario Central”.

◦ Modificar la aplicación para que el Show, antes de comenzar la actuación, obtenga una referencia al escenario y muestre por pantalla:

Bienvenidos al Escenario Central

(Resuelto en trabajo 17.0)

Page 53: Spring framework

Es posible que un determinado bean requiera hacer operaciones de inicialización antes de poder realizar su tarea, o bien liberar recursos –conexiones a bbdd, cierre ficheros, etc- antes de su destrucción.

Los atributos:◦ init-method

◦ destroy-method

nos permiten decirle al contenedor qué dos métodos queremos que realicen estas tareas de inicialización y destrucción.

Al igual que con autowire, se pueden especificar los nombres de los métodos constructor y destructor a nivel de contenedor con default-init-method y default-destroy-method.

Page 54: Spring framework

A partir de trabajo 17.0:◦ Implementar en el saxofón y en la armónica un

método afinar y otro limpiar que publiquen sendos mensajes por la consola.

◦ Hacer que ambos se disparen como método de inicialización y método de destrucción.

◦ Probarlo. ¿Funciona?

◦ ¿Y si ahora lo pongo por defecto para todos los beans?

<beans

default-init-method="afinar"

default-destroy-method="limpiar">

Page 55: Spring framework

Modificar y extender la clase Escenario para que tenga los métidos◦ abrirTelon

◦ cerrarTelon

Que impriman sendos mensajes y que sea invocado al inicializar y al destruir la clase.

Page 56: Spring framework

A partir del ejemplo anterior una vez terminado, probar a forzar a que la clase Instrumentista implemente las interfaces◦ InitializingBean

◦ DisposableBean

¿Qué ocurre? Hacer lo necesario para que sea compilable y ejecutarlo.

Resuelto en piloto 18.0

Page 57: Spring framework

Modificar la clase Escenario de nuevo para que la inicialización y destrucción se realicen ahora por usando los dos interfaces:◦ InitializingBean

◦ DisposableBean

Page 58: Spring framework
Page 59: Spring framework

Hasta ahora hemos declarado los beans de forma individual, estableciendo las propiedades de cada uno una a una de forma específica.

Problema: Puede degenerar en ficheros de configuración muy extensos y poco tratables.

Ejemplo:◦ Tenemos muchos beans de un determinado tipo

que comparten características ->Tenemos que definir la misma característica en todos ellos.

◦ En una orquesta, todos los instrumentistas tocan la misma canción

Page 60: Spring framework

Al igual que en la POO, es posible definir relaciones padre-hijo entre los beansdeclarados en un contenedor.

Un bean que extiende la declaración de otro bean se define como sub-bean del segundo.

Dos atributos específicos para esto:◦ Parent: Declara de qué bean hereda el que estamos

declarando

◦ Abstract: Declara el bean como abstracto, y por lo tanto, no instanciable.

Page 61: Spring framework

<bean id=“<nombre padre>" class=“<clase del padre>"

abstract="true">

<property name=“<propiedad común>" ref=“<ref bean a

heredar>"/>

</bean>

<bean id=”<hombre hijo 1>" parent=”<nombre padre>">

<property name=“<otra propiedad>" value=“<valor 1>"/>

</bean>

<bean id=”<hombre hijo 2>" parent=”<nombre padre>">

<property name=“<otra propiedad>" value=“<valor 2>"/>

</bean>

Page 62: Spring framework

Modificar el piloto a partir de su versión 18 para que:◦ Aparezca un bean Saxofonista que:

Sea abstracto

Esté ligado al Saxofón

◦ En el show participe un nuevo saxofonista con id=“bill” y nombre=“Bill Clinton”. Será presentado como “El presidente Clinton!”.

Resuelto en trabajo 19.0

Page 63: Spring framework

Extender ahora el piloto 19.0 para que:◦ Tanto los instrumentistas como los hombres

orquesta tengan un atributo de tipo String que se llame tema.

◦ Poner a todos los implicados de acuerdo para que toquen “Paquito el Chocolatero”

...

¿Se repite configuración?

¿Debemos ligar el atributo tema a la clase Actor?

¿Y el malabarista?

¿Creamos una nueva clase intermedia?

Page 64: Spring framework

En determinados contextos, puede que necesitemos compartir valores de propiedades entre beans de diferentes clases.

Spring permite hacer esto declarando un bean abstracto sin especificar su clase, y forzando a los hijos a que lo extiendan.

<bean id=“<bean base>" abstract="true">

<property name=“<nombre propiedad compartida>"

value=“<valor de la propriedad>" />

</bean>

Page 65: Spring framework

Definir un bean abstracto Interprete que defina el valor de la propierdad tema para que toque “Paquito el chocolatero” y configurar los bean “Hombre Orquesta” y “Saxofonista” para que hereden dicha propiedad del intérprete.

(Resuelto en piloto 20.0)

Page 66: Spring framework

Habitual el lenguajes dinámicos como Ruby. Consiste en añadir nuevos métodos a una

clase ya compilada, o modificar la definición de alguno ya existente.

En Java y otros LOO “clásicos” no se puede hacer esto, son “poco flexibles”

Spring permite “simular” la inyección de métodos en los beans que tenga declarados en el contenedor. Dos tipos:◦ Remplazo de métodos◦ Inyección de Getter

Page 67: Spring framework

Spring interceptará las invocaciones que se realicen al método sustituido para inyectar en medio la nueva implementación del mismo

Es necesario implementar un objeto que cumpla la interfaz MethodReplacer

public class <Nombre Clase> implements MethodReplacer {

public Object reimplement(Object target, Method method,

Object[] args) throws Throwable {

...

}

Page 68: Spring framework

Una vez dado de alta, sustituimos el método en el beans.xml

<bean id="<bean sustituto>"

class=“<clase method replacer>"/>

<bean ...>

...

<replaced-method name=“<método a sustituir>”

replacer=“<bean sustituto>"/>

</bean>

Page 69: Spring framework

Descargar piloto 20.0 (importante partir de éste, incluye nuevas referencias a jars) y extenderlo para sustituir el sonido del saxofón. Para ello:◦ Implementar una clase Sintentizador que modifique el

sonido del saxofón, retornando una nueva cadena de sonido.

◦ Darlo de alta en el beans.xml como sintentizador y utilizar el elemento replaced-method en el beansinstrumento para sobrescribir el método toca.

◦ ¿Funciona? ¿Qué clase está realmente ejecutándose? Añadir a la nueva cadena de sonido la referencia al objeto que se ejectura (Wrapper).

Resuelto en Versión 21.0(Ojo!!! Sólo funciona si obtenemos el objeto a través de

Spring!

Page 70: Spring framework

Si el método que queremos inyectar es un método getter para que retorne un beancontenido en el contenedor, podemos directamente obviar su implementación y decirle a Spring que intercepte la petición.

<bean id=“<nombre bean>” class=“<clase del bean>”>

<lookup-method name=“<nombre getter>" bean=“<bean a

retornar>"/>

</bean>

Page 71: Spring framework

Vamos a darle “el cambiazo” a kenny, sustituyéndole el saxofón por la guitarra fender.

Para ello,◦ Modificamos el método actua de la clase Instrumentista

para que cuando acceda al instrumento lo haga a través de su método getter.

◦ Transformamos el inner bean fender en uno normal para que pueda ser accedido desde otros beans.

◦ Sobrescribimos el getter de kenny para que getInstrumento retorne el bean fender.

(Resuelto en piloto 21.0)¿Qué clase está realmente implementando el método

actúa?

Page 72: Spring framework

Las propiedades vistas hasta ahora son simples, pero normalmente nos enfrentamos a estructuras más complejas

Ej: Reconocer y procesar una URL:http://www.xmethods.net/sd/BabelFishService.wsdl

Spring, puede convertir automáticamente el texto anterior en un objeto de tipo URL. ¿Cómo lo hace? Mediante un property editorbasado en la especificación de Java Beans.

Page 73: Spring framework

Interfaz java.beans.PropertyEditor

Permite especificar como se deben mapear datos de tipo String en tipos no String.

Fuerza a tener dos métodos:◦ getAsText()- Devuelve la representación en forma de

String del valor◦ setAsText(String) – Transforma el String que recibe en el

formato correspondiente.

Si se trata de dar un valor de tipo String a una propiedad que no lo es, se disparará el método setAsText() para realizar la conversión.

getAsText() se usará para representar el valor.

Page 74: Spring framework

Spring incorpora varios editores de propiedades a medida, basados en la clase PropertyEditorSupport.

PropertyEditor Utilidad

ClassEditor Transforma un String en una propiedad de tipo java.lang.Class.

CustomDateEditor Transforma de String a java.util.Date

FileEditor Transforma de String a java.io.File

LocaleEditor Transforma de String a java.util.Locales

StringArrayPropertyEditor De una lista de Strings con comas a un array de Strings

StringTrimmerEditor Hacer trim sobre el String.

URLEditor Transforma de String a URL

Page 75: Spring framework

Podemos desarrollar nuestro propio editor de propiedades personalizado para nuestra aplicación.

Ejemplo (A partir de piloto 22.00): Vamos a añadir información de contacto a todos los instrumentistas.

Creamos una clase Telefono con los atributos ◦ codigoPais◦ numero◦ extension

Y sus correspondientes getters y constructor parametrizado.

Page 76: Spring framework

Añadimos una instancia de la clase Telefono como propiedad de la clase Instrumentista

Y ahora configuraremos el contenedor para asignarle un teléfono a Kenny G.

<bean id="telefono1" class="es.uniovi.si.Telefono">

<constructor-arg value="0034"/>

<constructor-arg value="985105094"/>

<constructor-arg value="00"/>

</bean>

<bean id="kenny" parent="Saxofonista">

<property name="nombre" value="Kenny G"/>

<property name="telefono" ref="telefono1"/>

<lookup-method name="getInstrumento" bean="fender"/>

</bean>

¿Funciona? Sí, pero es tedioso y poco práctico

Page 77: Spring framework

Alternativa: Creamos nuestro propio PropertyEditor:

public class TelefonoPropertyEditor extends PropertyEditorSupport {

public void setAsText(String texto){

String stripped = stripNonNumeric(texto);

String codigoPais = stripped.substring(0,3);

String numero = stripped.substring(3,12);

String extension = stripped.substring(12);

Telefono telefono = new Telefono(codigoPais, numero, extension);

setValue(telefono);}

private String stripNonNumeric(String original) {

StringBuffer allNumeric = new StringBuffer();

for(int i=0; i<original.length(); i++) {

char c = original.charAt(i);

if(Character.isDigit(c)) {

allNumeric.append(c);

}

}

return allNumeric.toString();}

}

Page 78: Spring framework

Ahora sólo nos falta decirle a Spring cuando y como aplicar el nuevo property editor, por medio del CustomEditorConfigurer

CustomEditorConfigurer es un BeanPostProcessor que carga los editores de propiedades en la BeanFactory. Para ello:

<bean

class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="customEditors">

<map>

<entry key="es.uniovi.si.Telefono">

<bean id="TelefonoEditor"

class="es.uniovi.si.TelefonoPropertyEditor">

</bean>

</entry>

</map>

</property>

</bean>

Page 79: Spring framework

Ahora ya podemos asignárselo directamente a kenny

<bean id="kenny" parent="Saxofonista">

<property name="nombre" value="Kenny G" />

<property name="telefono" value="0034-650423932-00" />

<lookup-method name="getInstrumento" bean="fender" />

</bean>

(Resuelto en piloto 23.0)

Page 80: Spring framework

Creamos ahora un propertyEditor para el email:◦ Creamos una clase email con dos propiedades: usuario y

servidor. Hacemos sus accessors y su constructor parametrizado

◦ Añadimos Email como propiedad de instrumentista◦ Creamos el properyeditor para convertir el emailemail.setUsuario(texto.substring(0,texto.indexOf('@')));

email.setServidor(texto.substring(

texto.indexOf('@')+1,texto.length()));

◦ Añadimos el nuevo email property editor al map del CustomEditorConfigurer

◦ Le asignamos [email protected] al bean bill.Resuelto en 23.5

Page 81: Spring framework

La mayoría de los beans que manejará el contenedor son tratados de la misma forma –la vista hasta ahora.

Para determinadas tareas, Spring permite especificar que determinados beans sean tratados de manera especial.

Para marcar aquellos beans que deben ser tratados como tales, nos serviremos de la inyección de dependencias por interfaces.

Page 82: Spring framework

Mediante estos, podemos:◦ Tomar parte en la creación de los beans y en el

ciclo de vida de la factoría mediante posprocesamiento.

◦ Cargar ficheros de configuración externos –en ficheros property

◦ Cargar mensajes de texto, como base para la internacionalización.

◦ Ligar el bean a la recepción de eventos.

Page 83: Spring framework

Permiten programar ciertas tareas que se dispararán antes y después de la inicialización de los beans del contenedor

El bean de PostProcesamiento se configura POR CONTENEDOR

Para esto, tenemos que:◦ Crear un bean que implemente la interfaz

BeanPostProcessor

◦ Darlo de alta en el contenedor.

Page 84: Spring framework

El bean debe implementar la interfaz BeanPostProcessor:

public interface BeanPostProcessor

{

Object postProcessBeforeInitialization( Object bean,

String name) throws BeansException;

Object postProcessAfterInitialization( Object bean,

String name) throws BeansException;

}

Page 85: Spring framework

Tenemos dos alternativas:◦ Si trabajamos con BeanFactory:

BeanPostProcessor fuddifier = new Fuddifier();

factory.addBeanPostProcessor(fuddifier);

◦ Si trabajamos con ApplicationContext:<bean class=“<nombre de la clase postprocesadora>"/>

En el segundo caso, basta con esto. El propio contenedor se dará cuenta de que el bean instanciado implementa la interfaz BeanPostProcessor y lo incluirá como tal en el ciclo de vida de los beans corrientes.

Page 86: Spring framework

Queremos desarrollar un postprocesador que “se chive” de quienes están actuando en el Show, de forma que para todo aquel beanque tenga nombre (y por lo tanto, método getNombre()), se genere un mensaje por pantalla notificando que “fulanito” ha actuado.

Para ello, habrá que ◦ desarrollar el postprocesador

◦ darlo de alta en el contenedor

Page 87: Spring framework

public class HaciendaPostProcessor implements BeanPostProcessor {

@Override

public Object postProcessAfterInitialization(Object bean, String arg1)

throws BeansException {

try {

Method method= bean.getClass().getMethod("getNombre");

if ( method!=null ){

String nombre = (String) method.invoke(bean, null);

System.out.println("\t\tREGISTRADA ACTUACIÓN DE "+nombre);

}

}

catch (NoSuchMethodException e) {

//No hacemos nada.

} catch (Exception ee) {

ee.printStackTrace();

}

return bean;

}

@Override

public Object postProcessBeforeInitialization(Object bean, String arg1)

throws BeansException {

return bean;

}

}

Page 88: Spring framework

Y lo damos de alta en el contenedor<bean class="es.uniovi.si.HaciendaPostProcessor"/>

Resuelto en Piloto 24.0

Taller práctico Descargar el piloto 24.0

Importarlo en Eclipse

Examinar el código fuente

Page 89: Spring framework

Ahora llega la SGAE!

Extender el piloto par añadir un nuevo beanpostprocesador SGAEPostProcessor que saque por pantalla todos aquellos temas que se toquen en el Show, intentando acceder al método getTema de cada bean declarado en el mismo.

(Será necesario añadir el método getTema() a los que ya cuentan con setTema())

(Resuelto en piloto 25.0).

Page 90: Spring framework

Similar al BeanPostProcessor, el BeanFactoryPostProcessor permite realizar tareas de postprocesamiento sobre todo el contenedor de Spring.

public interface BeanFactoryPostProcessor {

void postProcessBeanFactory(

ConfigurableListableBeanFactory beanFactory)

throws BeansException;

}

El método postProcessBeanFactory es invocado por Spring una vez las definiciones hayan sido cargadas, pero antes de que los beanssean instanciados.

Page 91: Spring framework

Ejemplo: Para saber cuantos beans han sido declarados en el beans.xml

public class BeanCounter implements BeanFactoryPostProcessor {

private Logger LOGGER = Logger.getLogger(BeanCounter.class);

public void postProcessBeanFactory(

ConfigurableListableBeanFactory factory) throws

BeansException {

LOGGER.debug("BEAN COUNT: " +

factory.getBeanDefinitionCount());

}

}

Para darlo de alta en el contenedor.<bean id="beanCounter”class="com.spring.BeanCounter"/>

Page 92: Spring framework

Es posible configurar los beans mediante el beans.xml y el elemento <property>.

Sin embargo, no conviene mezclar el cableado de beans con la configuración específica de nuestra aplicación.

Spring proporciona el objeto PropertyPlaceholderConfigurer si trabajamos con el ApplicationContext para esto.

<bean id="propertyConfigurer"

class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="location" value=“<fichero.properties>" />

</bean>

Page 93: Spring framework

Puede que necesitemos modular la configuración en diferentes ficheros de propiedades:

<bean id="propertyConfigurer"

class="org.springframework.beans.factory.config.PropertyPl

aceholderConfigurer">

<property name="locations">

<list>

<value>jdbc.properties</value>

<value>security.properties</value>

<value>application.properties</value>

</list>

</bean>

Page 94: Spring framework

Ahora podemos recuperar los valores de configuración referenciándolos por medio de variables en lugar de tenerlos “hardcodeados” en el beans.xml

<bean id="dataSource” class=

"org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="url” value="${database.url}" />

<property name="driverClassName” value="${database.driver}" />

<property name="username” value="${database.user}" />

<property name="password” value="${database.password}" />

</bean>

Page 95: Spring framework
Page 96: Spring framework

Extender el piloto 25.0 para que tome los siguientes datos del fichero Configuracion.properties:

numero.malabares=25

tema=19 días y 500 noches

(Resuelto en piloto 26.0)

Page 97: Spring framework

En determinados casos, los beans necesitarán tener acceso a objetos de Spring, como el ApplicationContext.

Esto se resuelve mediante inyección de dependencias por interfaz. Hay tres posibles interfaces que dan acceso a sendos objetos:◦ BeanNameAware

◦ BeanFactoryAware

◦ ApplicationContextAware

Page 98: Spring framework

Implementando la interfaz BeanNameAware le estoy diciendo al contenedor que queremos que nos inyecte el identificador con el que el bean ha sido declarado en el beans.xmlpublic interface BeanNameAware {

void setBeanName(String name);

}

Cuando cada bean sea cagado, el contenedor comprobará por introspección si implementa esta interfaz ( isInstanceOf(…)).

En tal caso, invocará su método setBeanName(…) pasándole como parámetro el identificador del bean.

Page 99: Spring framework

De la misma forma, accedemos a la factoría y al contexto:

public class StudentServiceImpl implements StudentService,

ApplicationContextAware

{

private ApplicationContext context;

public void setApplicationContext(ApplicationContext context)

{

this.context = context;

}

}

Page 100: Spring framework

Modificar el piloto 26.0 par que:◦ La clase Malabarista reciba y almacene

Contexto

La factoría

Su nombre

◦ Forzar además a que cuando reciba su nombre, muestre un mensaje diciendo:

“Hola, me llamo actor”

(Resuelto en piloto 27.0)

Page 101: Spring framework

La inyección de dependencias no es la única forma de interacción entre beans en Spring.

La otra alternativa es basarse en el modelo de eventos de los JavaBeans.

Un bean publicador dispara un evento que será recibido por todos aquellos que estén registrados como escuchadores.

El publicado y los escuchadores (listeners) no se conocen entre sí, están desacoplados.

Page 102: Spring framework

Es Spring un bean puede ser◦ Publisher

◦ Listener

◦ Ambos dos.

Page 103: Spring framework

Un evento para poder ser gestionado por Spring debe extender la clase ApplicationEvent.

public class CourseFullEvent extends ApplicationEvent {

private Course course;

public CourseFullEvent(Object source, Course course) {

super(source);

this.course = course;

}

public Course getCourse() {

return course;

}

}

Page 104: Spring framework

Una vez creado… ¿Cómo lo publicamos?

El objeto ApplicationContext tiene el método publishEvent(), que nos permite publicar instancias de la clase ApplicationEvent.

Todo aquel bean ApplicationListener registrado en el contenedor recibirá el evento mediante una llamada a su método onApplicationEvent()

ApplicationContext context = …;

Course course = …;

context.publishEvent(new CourseFullEvent(this, course));

Problema: Necesitamos hacer que un bean sea capa de procesar eventos.

¿Cómo se hace eso?

Page 105: Spring framework

Para que un bean dado de alta en el contenedor reciba eventos que extiendan la clase ApplicationEvent, deberá implementar la Interfaz ApplicationListener

Public interface ApplicationListener

{

public void onApplicationEvent(ApplicationEvent event);

}

El contenedor detecta que es listener de los eventos y lo añade automáticamente a la suscripción.

Page 106: Spring framework

Extender el piloto 27 para que:◦ Aparezca una clase Representante y un bean de su

tipo declarado en el contendor.

◦ Aparezca un evento PaseEvent con un método getActor() que retorne la instancia de Actor que actúa en el Show.

◦ El bean Show lance un evento PaseEvent por cada actor que actúe para que el Representante lo escuche y tome nota de cuanto debe facturar al gestor.

(Resuelto en el piloto 28.0)

Page 107: Spring framework

El show va a ser retransmitido por televisión, y por lo tanto, es necesario avisar al técnico de control para que cuando termine una actuación importante, pase a publicidad, y cuando comience la siguiente importante, retome la conexión con el escenario.

La tele sólo se interesa por las grandes personalidades como Kenny G y Bill Clinton, pero para mantener al público viendo los anuncios, los ponemos al comienzo y fin de espectáculo.

Para modelar esto, vamos a necesitar crear dos tipos de eventos diferentes que representen el comienzo y el final de una actuación. En el primero además enviaremos el actor participa en el mismo.

Page 108: Spring framework

Tendremos que:◦ Creamos dos nuevos eventos: ComienzoVIPEvent – con una propiedad Actor

FinVIPEvent

◦ Modificar la clase Show para que cuando comiencen bill o kenny se dispare el correspondiente evento, así como cuando finalicen.

◦ Implementar TecnicoTelevision y dar de alta al bean“urdazi” como tal. Tiene que ser capaz de escuchar eventos de tipo ApplicationEvent, y publicar los mensajes de inicio y fin de la retransmisión, dependiendo del evento que le llegue.

Resuelto en piloto 28.5

Page 109: Spring framework

Programación Orientada a Aspectos

Page 110: Spring framework

Fue presentada en público por Gregor Kickzales y su equipo de investigación de Palo Alto Research Center en 1996.

Paradigma de programación relativamente reciente.

De esta forma se consigue:◦ Razonar mejor sobre los conceptos.◦ Eliminar la dispersión del código.◦ Implementaciones resultan más comprensibles,

adaptables y reusables.

Page 111: Spring framework

“ Un aspecto es una unidad modular que se disemina por la estructura de otras unidades funcionales. Los aspectos existen tanto en la

etapa de diseño como en la de implementación. Un aspecto de diseño es una

unidad modular del diseño que se entremezcla en la estructura de otras partes

del diseño. Un aspecto de programa o de código es una unidad modular del programa que aparece en otras unidades modulares del

programa (G. Kiczales) ”

Page 112: Spring framework

Los aspectos son la unidad básica de la POA, y pueden definirse como las partes de una aplicación que describen las cuestiones claves relacionadas con la semántica esencial o el rendimiento.

También pueden verse como los elementos que se diseminan por todo el código y que son difíciles de describir localmente con respecto a otros componentes.

Ej.: patrones de acceso a memoria, sincronización de procesos concurrentes, manejo de errores, etc.

Page 113: Spring framework
Page 114: Spring framework

Se muestra un programa como un todo formado por un conjunto de aspectos más un modelo de objetos.

Con el modelo de objetos se objetos se recoge la funcionalidad de negocio.

Los aspectos recogen características de rendimiento, infraestructura y otras no relacionadas con el modelo de negocio.

Page 115: Spring framework

Extraer y centralizar en un solo punto los "crosscutting concepts“ cada decisión se toma en un lugar concreto y no diseminada por la aplicación.

Minimizar las dependencias entre ellos desacoplar los distintos elementos que intervienen en un programa.

Page 116: Spring framework

Idea principal es centralizar en un solo punto todos los aspectos comunes a las clases que forman el sistema software.

Comportamiento

propio

Comportamiento

propio

Persistencia

Traza

……..

Comportamiento

propio

Comportamiento

propio

Persistencia Traza

Clase A Clase B

Clase A Clase B

Clases

Aspectos

Figura 1. Evolución de un sistema OO a uno OA

Page 117: Spring framework

Un código menos enmarañado, más natural y más reducido.

Mayor facilidad para razonar sobre los conceptos, ya que están separados y las dependencias entre ellos son mínimas.

Un código más fácil de depurar y más fácil de mantener.

Page 118: Spring framework

Se consigue que un conjunto grande de modificaciones en la definición de una materia tenga un impacto mínimo en las otras.

Se tiene un código más reusable y que se puede acoplar y desacoplar cuando sea necesario.

Page 119: Spring framework
Page 120: Spring framework

Punto de enlace

(Join Point)

Una posición bien definida dentro del código

orientado a objetos, por ejemplo, la declaración de

un método.

Punto de corte

(Pointcut)

Un conjunto de condiciones aplicadas a un punto de

enlace que, al cumplirse, activarán el punto de corte

y se ejecutará el punto de ejecución asignado a

dicho punto de corte.

Punto de

ejecución o

consejo (Advice)

Fragmento de código que se ejecuta cuando se

activa un punto de corte.

Aspe

cto

Page 121: Spring framework

Objetivo (target) El objetivo o target es el objeto sobre el que se va a aplicar

el aspecto, (Advised object), el objeto aconsejado.

Proxy Es el objeto resultante tras aplicar el Advice al objeto

objetivo. Desde el punto de vista del cliente, el objeto objetivo

(preAOP) y el objeto Proxy (postAOP) son el mismo

(transparente)

Weaving Tejido de aspectos: Proceso por el cual se mezcla el código

del modelo OO con los aspectos involucrados en su

ejecución

Page 122: Spring framework

La POA no rompe con las técnicas de programación orientadas a objetos sino que las complementa y extiende.

El nuevo paradigma de la programación orientada a aspectos es soportado por los llamados lenguajes de aspectos, que proporcionan constructores para capturar los

elementos que se diseminan por todo el sistema.

Page 123: Spring framework

Para tener un programa orientado a aspectos

necesitamos definir los siguientes

elementos:•Un lenguaje para definir la funcionalidad básica. Este

lenguaje se conoce como lenguaje base. Suele ser un

lenguaje de propósito general, tal como C++, C# o Java.

En general, se podrían utilizar también lenguajes no

imperativos.

•Uno o varios lenguajes de aspectos. El lenguaje de

aspectos define la forma de los aspectos, por ejemplo, los

aspectos de AspectJ se programan de forma muy

parecida a las clases.

•Un tejedor de aspectos.

Page 124: Spring framework

•Los puntos de enlace son una clase especial

de interfaz entre los aspectos y los módulos del

lenguaje de componentes.

•Son los lugares del código en los que éste se

puede aumentar con comportamientos

adicionales. Estos comportamientos se

especifican en los aspectos.

Page 125: Spring framework

El encargado de realizar este proceso de mezcla se conoce como tejedor (del término inglés weaver).

Se encarga de mezclar los diferentes mecanismos de abstracción y composición que aparecen en los lenguajes de aspectos y componentes ayudándose de los puntos de enlace.

El proceso de mezcla se puede retrasar para hacerse en tiempo de ejecución, o hacerse en tiempo de compilación.

Page 126: Spring framework

Estructura de una implementación en

los lenguajes tradicionales.

Page 127: Spring framework

Estructura de una implementación

en los lenguajes de aspectos.

Page 128: Spring framework

Los aspectos son tejidos en los objetos objetivo en los puntos de enlazado especificados (joinpoints).

Puede ser en tres momentos de la vida del objeto:◦ Tiempo de compilación – El código fuente del objetivo es

enriquecido con el código de los aspectos en los joinpoints, y luego compilado. Así trabaja AspectJ

◦ Durante la carga de clases – Los aspectos se enlazan en el momento de la carga de clases. Se requiere un ClassLoader especial.

◦ En tiempo de ejecución – Aplicando el patrón Proxy, se intercepta la petición y se delega en los aspectos cuando se requiere. Spring AOP trabaja de esta forma.

Page 129: Spring framework

Los advices en Spring están escritos en Java◦ Podemos usar IDEs corrientes

◦ Conocemos el lenguaje

Los pointcuts se declaran en un fichero XML◦ Estándar conocido. AspectJ requiere una sintaxis

especial.

Spring realiza el tejido de aspectos en tiempo de ejecución, sirviéndose del patrón Proxy.

Page 130: Spring framework

La ejecución el objeto “acosejado” por el aspecto es interceptada por un objeto Proxy que realiza las labores definidas en el pointcut.

Los proxies serán creados por el ApplicationContext cuando carga los beansdeclarados en el contenedor.

Dado que se crean en tiempo de ejecución, no se necesita ningún compilador específico para AOP con Spring.

Page 131: Spring framework

Dos tipos:◦ La clase aspectizada implementa un interfaz que

contiene los métodos por los que se van a realizar los pointcuts

Spring usa la java.lang.reflect.Proxy para generar automáticamente una nueva clase que implementa la ineterfaz, teje los aspectos e intercepta toda llamada a esos métodos de la interfaz.

◦ La clase es un POJO. Spring usa CGLIB para generar un proxy a medida en tiempo de compilación, extendiendo la clase objetivo (por lo que no podemos usar métodos final.)

Page 132: Spring framework

Spring implementa las interfaces de AOP Alliance:◦ Acuerdo para promover un uso estandarizado de la

AOP independientemente de la tecnología (Java) subyacente sobre la que se generen los aspectos.

◦ Un aspecto creado con estos interfaces es portable a otras plataformas AOP

Page 133: Spring framework

Spring sólo soporta Method Joinpoints

Otras plataformas (AspectJ, Aspect JBOSS) soportan field joinpoints, lo que permite aspectos más refinados.

No obstante, si todos los accesos a atributos se realizan por medio de los métodos accessor, se pueden emular los efectos.

Page 134: Spring framework

Tipo Interface Descripción

Around org.aopalliance.intercept.MethodInterceptor Intercepta las llamadas al método

Before org.springframework.aop.BeforeAdvice Se invoca antes de que el método sea invocado

After org.springframework.aop.AfterReturningAdvice Se invoca tras al método

Trhows org.springframework.aop.ThrowsAdvice Se invoca cuando el objetivo dispara una excepción.

Page 135: Spring framework

Vamos a probar los aspectos extendiendo el Espectáculo que ya tenemos funcionando, haciendo que aparezca un nuevo actor: el público.

Antes de nada, bajamos de la zona de descargas el jar de la CGLIB y lo añadimos en lib y al classpathdel proyecto actual.

Creamos una clase Audiencia con los siguientes métodos, y la declaramos como el bean audienciaen el beans.xml:

Método Muestra el mensaje

tomenAsiento() El público se sienta

apagueMoviles() El público apaga sus móviles

aplaudan() CLAP CLAP CLAP CLAP!!!!! BRAVO!!!!!

pedirDevolucion() BOOOOO!!!!!! Queremos nuestro dinero!!!!!!

Page 136: Spring framework

Ahora... ¿Quién invoca a la clase audiencia? El público no va dirigido ni por el actor de turno, ni por el propio espectáculo, sino que responden a situaciones automáticamente.

Vamos a crear un aspecto para que dispare los métodos del bean audiencia antes y después de cada actuación de un actor.

Page 137: Spring framework

Creamos una nueva clase Java es.uniovi.si.aop.AudienciaAdvice, de forma que:◦ Implemente: AfterReturningAdvice

MethodBeforeAdvice

ThrowsAdvice

◦ Tenga una propiedad audiencia para poder obtener una referencia a la misma por inyección.

◦ Implementamos los tres métodos, invocando a los métodos de audiencia que corresponda en cada contexto.

Page 138: Spring framework

Una vez creada la clase AudiencieAdvise, damos de alta el bean audiencieAdviceinyectando la audiencia como propiedad.

Ahora tenemos que definir el punto de corte.

Con el punto de corte le diremos a Spring donde exactamente queremos aplicar el advice que hemos implementado.

Spring permite utilizar varios tipos de puntos de corte.

Page 139: Spring framework

Objetivo: seleccionar los métodos sobre los que aplicar el advise.

Solución: Aplicación de un patrón de expresiones regulares sobre la signatura de los métodos

Spring incorpora dos clases que implementan estos puntos de corte:◦ org.springframework.aop.support.Perl5RegexpMeth

odPointcut (Requiere Jakarta ORO)◦ org.springframework.aop.support.JdkRegexpMetho

dPointcut (Usa el RegExp incorporado en Java 1.4)

Page 140: Spring framework

Para utilizar el punto de corte, primero tenemos que declararlo como bean en el contenedor:

<bean id=“actuacionPointcut"

class="org.springframework.aop.support.JdkRegexpMethodPointcut">

<property name="pattern" value=".*actua" />

</bean>

Este patrón encaja con cualquier método que se llame actua.

Page 141: Spring framework

Ahora tenemos que asociar el punto de corte con el advice:

<bean id="audienciaAdvisor"

class="org.springframework.aop.support.DefaultPointcutAdvisor">

<property name="advice" ref="audienciaAdvice" />

<property name="pointcut" ref="actuacionPointcut" />

</bean>

Con esto ya tenemos el aspecto completo implementado. Para que funcione, nos falta un último paso, la creación de los objetos proxy de los beans que queremos “aspectizar”

Page 142: Spring framework

Para todo bean “aconsejado” por un advisor, es necesario crear un proxy.

El proxy es el que realmente actuará cuando el advisor haga su trabajo, y por lo tanto, es el que realmente debemos “cablear”.

Para crear un proxy para el kenny, por ejemplo:

Page 143: Spring framework

<bean id="kenny"

class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="target" ref="kennyTarget" />

<property name="interceptorNames" value="audienciaAdvisor" />

<property name="proxyInterfaces” value="es.uniovi.si.Actor" />

</bean>

<bean id="kennyTarget" parent="Saxofonista">

<property name="nombre" value="Kenny G" />

<property name="telefono" value="0034-650423942-00" />

<lookup-method name="getInstrumento" bean="fender" />

</bean>

Creamos los proxies para el resto de los actores y ya podemos ejecutar la aplicación.

(Resuelto en Piltoto 29.0)

Page 144: Spring framework

Modificar el piloto 29.0 para que la guitarra dispare irremisiblemente una excepción de tipo Runtime() y comprobar que el público pide su devolución.

(Resuelto en piloto 30.0)

Page 145: Spring framework

La organización del espectáculo está preocupada por los controles de inmigración que la seguridad social está realizando sin previo aviso, así que decide poner un vigilante que, antes de cada actuación, le pida las credenciales a los artistas para dejarles trabajar o no.

Tendremos que seguir los siguientes pasos...

Page 146: Spring framework

Añadir a Actor un método getCredenciales que retorne un boolean (indicando si las tiene o no).

Creamos es.uniovi.si.VigilanteAdvise para que implemente BeforeAdvise, y lo damos de alta como vigilanteAdvise.

Implementamos el método before para que muestre un mensaje indicando si el target (tercer parámetro del método) tiene o no credenciales.

El punto de corte... Ya lo tenemos declarado! Será el mismo que para el ejemplo anterior

Asociamos el nuevo advisor con el punto de corte mediante el pointcutadvisor vigilanteAdvisor.

Finalmente, en el proxy, forzamos a que tenga en cuenta ambos interceptores:

<property name="interceptorNames" value="audienciaAdvisor,vigilanteAdvisor" />

Resuelto en piloto 31.0

Page 147: Spring framework

A partir del piloto 31.0, modificarlo para que:◦ el malabarista no tenga credenciales◦ El vigilante lance una excepción de tipo

InmigranteIlegalExcepcion avisando de que no puede trabajar.

◦ Ejecutarlo

¿Qué ha ocurrido? ¿Dónde deberíamos capturar la excepción para que la aplicación siga funcionando?

Capturarla en el lugar adecuado y mostrar un mensaje de la organización explicando la cancelación de la actuación.

(Resuelto en piloto 32.0)

Page 148: Spring framework
Page 149: Spring framework

Vamos a comenzar la implementación de una infraestructura base basada en Spring para el desarrollo de aplicaciones.

Desarrollaremos el esqueleto de una aplicación modelo sirviéndonos de Spring para ahorrarnos código que solemos tener que implementar para cada aplicación.

Page 150: Spring framework

Partir del último piloto manipulado y:◦ Eliminar todas las clases menos la factoría

◦ Dejar el beans.xml sin ningún bean para poder empezar de cero.

Vamos a partir de un entorno vacío sobre el cual trabajar.

Implementar la clase Main con método main y método comienzo. El main obtendrá una referencia a sí mismo por medio de la factoría e invocará su método comienzo.

Page 151: Spring framework

Queremos desarrollar un menú configurable que valga para cualquier aplicación de ventanas.

Cada elemento del menú (MenuItem) contendrá una descripción (description) y uno o varios subelementos, que serán inyectados por Spring.

Configurarlo para que de momento tenga la siguiente estructura:

Page 152: Spring framework

Archivo

Abrir

Edición

Cortar

Pegar

Acerca de

Finalmente, implementar un método printMenu en la clase

Main que pinte tabuladamente las diferentes opciones del

menú invocando el toString() de muniItem.

(Resuelto en piloto 40.0)

Page 153: Spring framework

Vamos a aplicar el patrón command. Para ello:◦ Implementaremos un interface

es.uniovi.si.menu.MenuCommand que contenga un método execute.

◦ Prepararemos el MenuItem para que:

Pueda recibir uno o varios Command por inyección, y los invoque en orden de inyección en un método run

◦ Creamos un comando (ejemplo, es.uniovi.si.comandos.AbrirCommand) para cada opción final del menú que de momento sólo mostrará un mensaje cuando se invoque, y los inyectamos en su correspondiente opción del menú.

(Resuelto piloto 41.0)

Page 154: Spring framework

Añadir a MenuItem una propuedad boolean active SIN INICIALIZAR, y modificarlo para que si vale false, el ´nombre del menú aparezca entre * al llamar al toString(). Ej: *Abrir*

Crear los eventos:

◦ es.uniovi.si.menu.event.AuthorizeMenuItemsEvent

◦ es.uniovi.si.menu.event.DenyMenuItemsEvent

◦ es.uniovi.si.menu.event.AuthorizeAllMenuItemsEvent

◦ es.uniovi.si.menu.event.DenyAllMenuItemsEvent

de forma que los dos primeros contengan una colección con los ids (tal y como han sido asignados en el beans.xml) de los menús a activar o desactivar.

Crear una clase MenuController, que implemente los métodos

◦ autorizeMenuItems(…)

◦ denyMenuItems(…)

◦ authorizeAll()

◦ denyAll()

de forma que se sirva de los eventos para activar o desactivar las opciones del menú que le soliciten cambiar. Las dos primeras podrán recibir uno o varios ids de tipo String.

Lo instanciamos como el bean “menuController” y se lo inyectamos a Main

Page 155: Spring framework

◦ Configurar el menú para que por defecto, todos los menús estén activos (¿uno a uno?), y cambiar lo necesario para que el menú pegar aparezca desactivado.

◦ Para probarlo, modificar el método comienzo de Main para que:

Pinte el menú

Desactive el menú de cortar

Pinte el menú

Active todas las opciones

Pinte el menú

(Resuelto en piloto 42.0)

Page 156: Spring framework

A estas alturas, decidimos que el no tiene sentido que Main contenga directamente el menú ni que implemente el método printMenu().

Refactorizamos la aplicación para que sea el MenúController el que contenga ambos elementos, de forma que el Main sólo interactúe con el menúController.

(Resuelto en piloto 43.0)

Page 157: Spring framework

Añadir un servicio de log tal que:◦ La interfaz de acceso sea

es.uniovi.si.infraestructura.log.Log y tenga los métodos: log

warn

error

fatalError

◦ La clase que lo implemente sea es.uniovi.si.infraestructura.log.MiLog

◦ La clase Main tenga acceso al log y muestre un mensaje para corroborar que funciona.

Page 158: Spring framework

Implementamos el LogAdvice para que:

◦ Al entrar trace un mensaje notificando que se ha invocado el método X de la clase Y con los argumentos Z

◦ Al salir muestre un mensaje notificando el final del método X de la clase Y retornando Z

◦ Al capturar una excepción notifique un error.

Creamos la interfaz MenuItemInterface, dado que para interceptar las invocaciones el advice requiere un interfaz (que luego implementará el Proxy). Ahora el MenuItemcontendrá elementos de tipo MenuItemInterface (lo hace solo eclipse!)

Creamos el pointcut para que capture invocaciones a los métodos run de los menús

Modificar el printMenu para que invoque cada método run.

Aspectizamos menuAbrir y probamos.

(Resuelto en piloto 44.0)

Page 159: Spring framework

Implementamos ahora un aspecto materializado en es.uniovi.si.infraestructura.security.SecurityAdvice de forma que:

◦ Reciba un objeto de tipo User en un atributo usuario con un método getUser que retorne el id del usuario.

◦ Reciba un String[] con los usuarios autorizados a ejecutar la aplicación

◦ Prepararlo para que antes de la invocación del método interceptado compruebe que el usuario tiene permisos para usar la aplicación

◦ Se dispare antes de cada comando del menú

La clase Main inicializará el bean User antes de invocar la impresión del menú.

(Resuelto en trabajo 45.0)