SlideShare una empresa de Scribd logo
1 de 159
   Spring es un framework ligero para el
    desarrollo de aplicaciones.
   Strtus, WebWork y otros son frameworks para
    web. Spring, por contra, da soporte a todas
    las capas de una aplicación.
   Nos evita “la fontanería” que normalmente el
    desarrollador se ve obligado a implementar a
    mano.
   Publicado en 2002/2003 por Rod
    Johnson y Juergen Holler
   Empezó siendo un ejemplo en el libro
    Expert One-on-One J2EE Design and
    Development de Rod Johnson.
   Spring 1.0 se publica en marzo del
    2004
   A partir de 2004/2005 Spring se
    populariza como framework de
    desarrollo para aplicaciones Java/J2EE
   Spring no es un servidor de aplicaciones JEE,
    sino que se integra en las aplicaciones que se
    despliegan sobre ellos, y sobre aplicaciones
    Java en general.
   Spring sustituye ¿elegantemente? algunos de
    los servicios que aportan los servidores de
    aplicaciones JEE.
   Spring propone una estructura consistente para
    toda la aplicación
   Facilita un método consistente para pegar todos
    los 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ándo
    al desarrollador la tarea de implementar tareas
    derivadas de la integración de los componentes de
    la aplicación.
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 coste
  adicional de implementación. Spring lo facilita
  reduciendo la implementación desacoplada
  basándose en interfaces.
 La especificación de JavaBeans ofrece ciertas
  ventajas 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
   Filosofía POJO, menos interfaces y excepciones
    chequeadas que fuerzan a complicar el código
    cuando integramos elementos diferentes.
   La prueba del software son esenciales. Spring nos
    ayuda a implementar código chequeable mediante
    pruebas unitarias.
   La aplicación de Spring debe ser placentera.
   El código de la aplicación no debe depender de las
    APIs de Spring.
   Spring no debe competir con soluciones que ya
    funcionan, sino permitir su fácil integración en la
    aplicación (Ej, Hibernate, JDO, etc.)
from springframework.org
¿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íciles
 de testear.
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.
   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)
   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?
   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áctico
Completar 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)
   El BeanFactory es una implementación del
    patrón factoría que permite crear beans
    declarándolos en un ficheros XML cuya
    raiz 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 que
      implementará el bean bautizado con id
   Por defecto, los beans son tratados como
    singletons (Dessign patterns, GoF’94),
  aunque existen otros posibles patrones de
  comportamiento.
Ejemplo:
                                           The bean’s fully-
                           The bean’s ID   qualified classname
      <beans>
        <bean id=“widgetService”
            class=“com.zabada.base.WidgetService”>
      </bean>
      </beans>
   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
   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>
   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)
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   Si existen BeanPostProcessors, Spring invoca su
inicialización)            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()
   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)
   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"/>
   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 WidgetServiceImpl
    deberá tener un método
    setWidgetDAO(WidgetServiceImpl ref)
   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)
   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).
   Hay tres implementaciones del contenedor:
              Tipo                            Descripción
ClassPathXmlApplicationContext    Carga el documento XML
                                  buscándolo en el classpath
FileSystemXmlApplicationContext   Lo busca en el sistema de ficheros
XmlWebApplicationContext          Lo busca como doc. XML contenido
                                  en una aplicación web.

    Ejemplo:
 ApplicationContext context = new
   FileSystemXmlApplicationContext("c:/foo.xml");
   Descargar la versión 8.0 del piloto y examinar
    el código fuente.
   Ejecutarlo para comprobar que funciona
    correctamente.
   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
   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?
   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)
   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
   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
   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)
   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" />
…
   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
   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:rrriaaannn
  riiiaaaannn 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
   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>
   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.
   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)
   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)
   Ú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
   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.
   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.
   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
   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)
   Si queremos definir un bean como prototype:

<bean id=<identificador>
    class=<nombre de la clase>
    scope={prototype
         |singleton
         |request
         |session
         |global-session/>
   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)
   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.
   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>" />
   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)
   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.
   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">
   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.
   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
   Modificar la clase Escenario de nuevo para
    que la inicialización y destrucción se realicen
    ahora por usando los dos interfaces:
    ◦ InitializingBean
    ◦ DisposableBean
   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
   Al igual que en la POO, es posible definir
    relaciones padre-hijo entre los beans
    declarados 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.
<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>
   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
   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?
   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>
   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)
   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
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 {
...
}
   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>
   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 beans
      instrumento 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!
   Si el método que queremos inyectar es un
    método getter para que retorne un bean
    contenido 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>
   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?
   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 editor
    basado en la especificación de Java Beans.
   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.
   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
   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.
   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
   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();}
}
   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.CustomEditorConfigure
  r">
  <property name="customEditors">
  <map>
        <entry key="es.uniovi.si.Telefono">
                 <bean id="TelefonoEditor"
                         class="es.uniovi.si.TelefonoPropertyEditor">
                 </bean>
        </entry>
  </map>
  </property>
</bean>
   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)
   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 email
    email.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 bill.clinton@whitehouse.org al bean bill.
                         Resuelto en 23.5
   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.
   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.
   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.
   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;
}
   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.
   Queremos desarrollar un postprocesador que
    “se chive” de quienes están actuando en el
    Show, de forma que para todo aquel bean
    que 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
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("ttREGISTRADA 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;
   }
}
   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
   Ahora llega la SGAE!
   Extender el piloto par añadir un nuevo bean
    postprocesador 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).
   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 beans
    sean instanciados.
   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"/>
   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.PropertyPlaceh
  olderConfigurer">
  <property name="location" value=“<fichero.properties>" />
</bean>
   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>
   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>
   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)
   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
   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.xml
    public 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.
   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;
  }
  …
}
   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)
   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.
   Es Spring un bean puede ser
    ◦ Publisher
    ◦ Listener
    ◦ Ambos dos.
   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;
  }
}
   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?
   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.
   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)
   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.
   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
Programación Orientada a Aspectos
   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.
“ 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) ”
   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.
   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.
   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.
   Idea principal es centralizar en un solo punto
     todos los aspectos comunes a las clases que
     forman el sistema software.
                                                                        C lases
          C lase A                     C lase B
                                                            C lase A               C lase B
      C om portam iento            C om portam iento
           propio                       propio         C om portam iento      C om portam iento
                                                            propio                 propio




                     P ersistencia


                          T raza

                                                       P ersistencia                T raza
                          … … ..
                                                                       A spectos


Figura 1. Evolución de un sistema OO a uno OA
   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.
   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.
Punto de enlace    Una posición bien definida dentro del código
            (Join Point)     orientado a objetos, por ejemplo, la declaración de
Aspecto

                             un método.
           Punto de corte    Un conjunto de condiciones aplicadas a un punto de
             (Pointcut)      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        Fragmento de código que se ejecuta cuando se
            ejecución o      activa un punto de corte.
          consejo (Advice)
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
   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.
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.
•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.
   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.
Estructura de una implementación en
     los lenguajes tradicionales.
Estructura de una implementación
  en los lenguajes de aspectos.
   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.
   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.
   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 beans
    declarados en el contenedor.
   Dado que se crean en tiempo de ejecución,
    no se necesita ningún compilador específico
    para AOP con Spring.
   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.)
   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
   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.
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.
   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 classpath
     del proyecto actual.
    Creamos una clase Audiencia con los siguientes
     métodos, y la declaramos como el bean audiencia
     en 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!!!!!!
   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.
   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.
   Una vez creada la clase AudiencieAdvise,
    damos de alta el bean audiencieAdvice
    inyectando 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.
   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)
   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.
   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”
   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:
<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)
   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)
   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...
 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
   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)
   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.
   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.
   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:
Archivo       Edición    Acerca de


               Abrir       Cortar

                            Pegar


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)
   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)
   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
◦ 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)
   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)
   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.
   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 MenuItem
    contendrá 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)
       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)

Más contenido relacionado

La actualidad más candente

Plataforma de programación Java
Plataforma de programación JavaPlataforma de programación Java
Plataforma de programación JavaAntonio Contreras
 
Orm hibernate springframework
Orm hibernate springframeworkOrm hibernate springframework
Orm hibernate springframeworkVortexbird
 
Introducción a Java EE
Introducción a Java EEIntroducción a Java EE
Introducción a Java EEPaco Saucedo
 
Introducción a java EE 7
Introducción a java EE 7Introducción a java EE 7
Introducción a java EE 7Carlos Camacho
 
9 tecnologías v1.1
9 tecnologías v1.19 tecnologías v1.1
9 tecnologías v1.1UTN
 
Curso Java Avanzado 1 IntroduccióN Al Desarrollo Web
Curso Java Avanzado   1 IntroduccióN Al Desarrollo WebCurso Java Avanzado   1 IntroduccióN Al Desarrollo Web
Curso Java Avanzado 1 IntroduccióN Al Desarrollo WebEmilio Aviles Avila
 
Sesion 3. desarrollo de aplicaciones jee
Sesion 3. desarrollo de aplicaciones jeeSesion 3. desarrollo de aplicaciones jee
Sesion 3. desarrollo de aplicaciones jeeHéctor Santos
 
Integración de aplicaciones Java
Integración de aplicaciones JavaIntegración de aplicaciones Java
Integración de aplicaciones JavaIker Canarias
 
Aplicaciones web con jakarta struts - Javier Oliver Fulguera
Aplicaciones web con jakarta struts  - Javier Oliver FulgueraAplicaciones web con jakarta struts  - Javier Oliver Fulguera
Aplicaciones web con jakarta struts - Javier Oliver FulgueraJavier Oliver Fulguera
 
UDA-Anexo configuración y uso de jackson
UDA-Anexo configuración y uso de jacksonUDA-Anexo configuración y uso de jackson
UDA-Anexo configuración y uso de jacksonAnder Martinez
 
Java lenguaje de desarrollo
Java lenguaje de desarrolloJava lenguaje de desarrollo
Java lenguaje de desarrolloDavid
 

La actualidad más candente (20)

Spring framework
Spring frameworkSpring framework
Spring framework
 
Herramientas Java
Herramientas JavaHerramientas Java
Herramientas Java
 
Web services y java
Web services y javaWeb services y java
Web services y java
 
Plataforma de programación Java
Plataforma de programación JavaPlataforma de programación Java
Plataforma de programación Java
 
Orm hibernate springframework
Orm hibernate springframeworkOrm hibernate springframework
Orm hibernate springframework
 
Frameworks J2EE
Frameworks J2EEFrameworks J2EE
Frameworks J2EE
 
Introducción a Java EE
Introducción a Java EEIntroducción a Java EE
Introducción a Java EE
 
Introducción a JEE
Introducción a JEEIntroducción a JEE
Introducción a JEE
 
spring
springspring
spring
 
Spring
SpringSpring
Spring
 
Introducción a java EE 7
Introducción a java EE 7Introducción a java EE 7
Introducción a java EE 7
 
Curso Java Avanzado 5 Ejb
Curso Java Avanzado   5 EjbCurso Java Avanzado   5 Ejb
Curso Java Avanzado 5 Ejb
 
9 tecnologías v1.1
9 tecnologías v1.19 tecnologías v1.1
9 tecnologías v1.1
 
Curso Java Avanzado 1 IntroduccióN Al Desarrollo Web
Curso Java Avanzado   1 IntroduccióN Al Desarrollo WebCurso Java Avanzado   1 IntroduccióN Al Desarrollo Web
Curso Java Avanzado 1 IntroduccióN Al Desarrollo Web
 
Spring mvc
Spring mvcSpring mvc
Spring mvc
 
Sesion 3. desarrollo de aplicaciones jee
Sesion 3. desarrollo de aplicaciones jeeSesion 3. desarrollo de aplicaciones jee
Sesion 3. desarrollo de aplicaciones jee
 
Integración de aplicaciones Java
Integración de aplicaciones JavaIntegración de aplicaciones Java
Integración de aplicaciones Java
 
Aplicaciones web con jakarta struts - Javier Oliver Fulguera
Aplicaciones web con jakarta struts  - Javier Oliver FulgueraAplicaciones web con jakarta struts  - Javier Oliver Fulguera
Aplicaciones web con jakarta struts - Javier Oliver Fulguera
 
UDA-Anexo configuración y uso de jackson
UDA-Anexo configuración y uso de jacksonUDA-Anexo configuración y uso de jackson
UDA-Anexo configuración y uso de jackson
 
Java lenguaje de desarrollo
Java lenguaje de desarrolloJava lenguaje de desarrollo
Java lenguaje de desarrollo
 

Similar a spring framework

Similar a spring framework (20)

Java beans en jsp
Java beans en jspJava beans en jsp
Java beans en jsp
 
Hands-on Spring 3: The next generation
Hands-on Spring 3: The next generationHands-on Spring 3: The next generation
Hands-on Spring 3: The next generation
 
SpringFramework Overview
SpringFramework OverviewSpringFramework Overview
SpringFramework Overview
 
Semana9 Vbr
Semana9 VbrSemana9 Vbr
Semana9 Vbr
 
Curso de Desarrollo Web 2
Curso de Desarrollo Web 2Curso de Desarrollo Web 2
Curso de Desarrollo Web 2
 
Capitulo3 jsf
Capitulo3 jsfCapitulo3 jsf
Capitulo3 jsf
 
Maven Overview
Maven OverviewMaven Overview
Maven Overview
 
La Arquitectura De Netbeans V2
La Arquitectura De Netbeans V2La Arquitectura De Netbeans V2
La Arquitectura De Netbeans V2
 
Springboot Overview
Springboot  OverviewSpringboot  Overview
Springboot Overview
 
Jsp servlet- Tutorial BD Conexión
Jsp servlet- Tutorial BD ConexiónJsp servlet- Tutorial BD Conexión
Jsp servlet- Tutorial BD Conexión
 
Manual Basico De Struts
Manual Basico De StrutsManual Basico De Struts
Manual Basico De Struts
 
Proyectos JAVA con maven
Proyectos JAVA con mavenProyectos JAVA con maven
Proyectos JAVA con maven
 
Proyectos java-con-maven
Proyectos java-con-mavenProyectos java-con-maven
Proyectos java-con-maven
 
Construccion a través de compontes
Construccion a través de compontesConstruccion a través de compontes
Construccion a través de compontes
 
Fondo1 (2)
Fondo1 (2)Fondo1 (2)
Fondo1 (2)
 
Un ejemplo sencillo con ejb
Un ejemplo sencillo con ejbUn ejemplo sencillo con ejb
Un ejemplo sencillo con ejb
 
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
 
OSGi
OSGiOSGi
OSGi
 
Ejb30 3
Ejb30 3 Ejb30 3
Ejb30 3
 
Spring mvc
Spring mvcSpring mvc
Spring mvc
 

spring framework

  • 1.
  • 2. Spring es un framework ligero para el desarrollo de aplicaciones.  Strtus, WebWork y otros son frameworks para web. Spring, por contra, da soporte a todas las capas de una aplicación.  Nos evita “la fontanería” que normalmente el desarrollador se ve obligado a implementar a mano.
  • 3. Publicado en 2002/2003 por Rod Johnson y Juergen Holler  Empezó siendo un ejemplo en el libro Expert One-on-One J2EE Design and Development de Rod Johnson.  Spring 1.0 se publica en marzo del 2004  A partir de 2004/2005 Spring se populariza como framework de desarrollo para aplicaciones Java/J2EE
  • 4. Spring no es un servidor de aplicaciones JEE, sino que se integra en las aplicaciones que se despliegan sobre ellos, y sobre aplicaciones Java en general.  Spring sustituye ¿elegantemente? algunos de los servicios que aportan los servidores de aplicaciones JEE.
  • 5. Spring propone una estructura consistente para toda la aplicación  Facilita un método consistente para pegar todos los 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ándo al desarrollador la tarea de implementar tareas derivadas de la integración de los componentes de la aplicación.
  • 6. 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 coste adicional de implementación. Spring lo facilita reduciendo la implementación desacoplada basándose en interfaces.  La especificación de JavaBeans ofrece ciertas ventajas 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
  • 7. Filosofía POJO, menos interfaces y excepciones chequeadas que fuerzan a complicar el código cuando integramos elementos diferentes.  La prueba del software son esenciales. Spring nos ayuda a implementar código chequeable mediante pruebas unitarias.  La aplicación de Spring debe ser placentera.  El código de la aplicación no debe depender de las APIs de Spring.  Spring no debe competir con soluciones que ya funcionan, sino permitir su fácil integración en la aplicación (Ej, Hibernate, JDO, etc.)
  • 9. ¿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íciles de testear.
  • 10. 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.
  • 11.
  • 12. 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)
  • 13. 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?
  • 14. 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áctico Completar 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)
  • 15. El BeanFactory es una implementación del patrón factoría que permite crear beans declarándolos en un ficheros XML cuya raiz 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 que implementará el bean bautizado con id
  • 16. Por defecto, los beans son tratados como singletons (Dessign patterns, GoF’94), aunque existen otros posibles patrones de comportamiento. Ejemplo: The bean’s fully- The bean’s ID qualified classname <beans> <bean id=“widgetService” class=“com.zabada.base.WidgetService”> </bean> </beans>
  • 17. 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
  • 18. 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>
  • 19. 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)
  • 20.
  • 21. 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 Si existen BeanPostProcessors, Spring invoca su inicialización) 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()
  • 22. 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)
  • 23. 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"/>
  • 24. 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 WidgetServiceImpl deberá tener un método setWidgetDAO(WidgetServiceImpl ref)
  • 25. 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)
  • 26. 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).
  • 27. Hay tres implementaciones del contenedor: Tipo Descripción ClassPathXmlApplicationContext Carga el documento XML buscándolo en el classpath FileSystemXmlApplicationContext Lo busca en el sistema de ficheros XmlWebApplicationContext Lo busca como doc. XML contenido en una aplicación web.  Ejemplo: ApplicationContext context = new FileSystemXmlApplicationContext("c:/foo.xml");
  • 28.
  • 29. Descargar la versión 8.0 del piloto y examinar el código fuente.  Ejecutarlo para comprobar que funciona correctamente.
  • 30. 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
  • 31. 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?
  • 32. 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)
  • 33. 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
  • 34. 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
  • 35. 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)
  • 36. 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" /> …
  • 37. 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
  • 38. 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:rrriaaannn riiiaaaannn 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
  • 39. 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>
  • 40. 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.
  • 41. 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)
  • 42. 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)
  • 43. Ú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
  • 44. 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.
  • 45. 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.
  • 46. 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
  • 47. 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)
  • 48. Si queremos definir un bean como prototype: <bean id=<identificador> class=<nombre de la clase> scope={prototype |singleton |request |session |global-session/>
  • 49. 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)
  • 50. 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.
  • 51. 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>" />
  • 52. 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)
  • 53. 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.
  • 54. 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">
  • 55. 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.
  • 56. 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
  • 57. Modificar la clase Escenario de nuevo para que la inicialización y destrucción se realicen ahora por usando los dos interfaces: ◦ InitializingBean ◦ DisposableBean
  • 58.
  • 59. 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
  • 60. Al igual que en la POO, es posible definir relaciones padre-hijo entre los beans declarados 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.
  • 61. <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>
  • 62. 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
  • 63. 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?
  • 64. 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>
  • 65. 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)
  • 66. 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
  • 67. 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 { ... }
  • 68. 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>
  • 69. 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 beans instrumento 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!
  • 70. Si el método que queremos inyectar es un método getter para que retorne un bean contenido 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>
  • 71. 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?
  • 72. 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 editor basado en la especificación de Java Beans.
  • 73. 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.
  • 74. 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
  • 75. 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.
  • 76. 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
  • 77. 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();} }
  • 78. 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.CustomEditorConfigure r"> <property name="customEditors"> <map> <entry key="es.uniovi.si.Telefono"> <bean id="TelefonoEditor" class="es.uniovi.si.TelefonoPropertyEditor"> </bean> </entry> </map> </property> </bean>
  • 79. 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)
  • 80. 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 email email.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 bill.clinton@whitehouse.org al bean bill. Resuelto en 23.5
  • 81. 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.
  • 82. 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.
  • 83. 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.
  • 84. 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; }
  • 85. 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.
  • 86. Queremos desarrollar un postprocesador que “se chive” de quienes están actuando en el Show, de forma que para todo aquel bean que 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
  • 87. 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("ttREGISTRADA 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; } }
  • 88. 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
  • 89. Ahora llega la SGAE!  Extender el piloto par añadir un nuevo bean postprocesador 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).
  • 90. 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 beans sean instanciados.
  • 91. 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"/>
  • 92. 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.PropertyPlaceh olderConfigurer"> <property name="location" value=“<fichero.properties>" /> </bean>
  • 93. 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>
  • 94. 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>
  • 95.
  • 96. 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)
  • 97. 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
  • 98. 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.xml public 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.
  • 99. 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; } … }
  • 100. 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)
  • 101. 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.
  • 102. Es Spring un bean puede ser ◦ Publisher ◦ Listener ◦ Ambos dos.
  • 103. 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; } }
  • 104. 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?
  • 105. 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.
  • 106. 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)
  • 107. 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.
  • 108. 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
  • 110. 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.
  • 111. “ 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) ”
  • 112. 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.
  • 113.
  • 114. 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.
  • 115. 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.
  • 116. Idea principal es centralizar en un solo punto todos los aspectos comunes a las clases que forman el sistema software. C lases C lase A C lase B C lase A C lase B C om portam iento C om portam iento propio propio C om portam iento C om portam iento propio propio P ersistencia T raza P ersistencia T raza … … .. A spectos Figura 1. Evolución de un sistema OO a uno OA
  • 117. 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.
  • 118. 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.
  • 119.
  • 120. Punto de enlace Una posición bien definida dentro del código (Join Point) orientado a objetos, por ejemplo, la declaración de Aspecto un método. Punto de corte Un conjunto de condiciones aplicadas a un punto de (Pointcut) 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 Fragmento de código que se ejecuta cuando se ejecución o activa un punto de corte. consejo (Advice)
  • 121. 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
  • 122. 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.
  • 123. 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.
  • 124. •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.
  • 125. 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.
  • 126. Estructura de una implementación en los lenguajes tradicionales.
  • 127. Estructura de una implementación en los lenguajes de aspectos.
  • 128. 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.
  • 129. 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.
  • 130. 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 beans declarados en el contenedor.  Dado que se crean en tiempo de ejecución, no se necesita ningún compilador específico para AOP con Spring.
  • 131. 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.)
  • 132. 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
  • 133. 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.
  • 134. 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.
  • 135. 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 classpath del proyecto actual.  Creamos una clase Audiencia con los siguientes métodos, y la declaramos como el bean audiencia en 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!!!!!!
  • 136. 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.
  • 137. 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.
  • 138. Una vez creada la clase AudiencieAdvise, damos de alta el bean audiencieAdvice inyectando 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.
  • 139. 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)
  • 140. 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.
  • 141. 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”
  • 142. 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:
  • 143. <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)
  • 144. 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)
  • 145. 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...
  • 146.  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
  • 147. 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)
  • 148.
  • 149. 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.
  • 150. 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.
  • 151. 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:
  • 152. Archivo Edición Acerca de Abrir Cortar Pegar 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)
  • 153. 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)
  • 154. 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
  • 155. ◦ 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)
  • 156. 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)
  • 157. 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.
  • 158. 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 MenuItem contendrá 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)
  • 159. 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)