Spring

RECU-0142 (Recurso Manual)

Descripción

Spring es un framework de aplicaciones Java/JEE desarrollado usando licencia OpenSource. Se basa en una configuración a base de javabeans bastante simple. Es potente en cuanto a la gestión del ciclo de vida de los componentes y fácilmente ampliable. Es interesante el uso de la programación orientada a aspectos (IoC). Tiene plantillas que permiten un uso más fácil de Hibernate, iBatis, JDBC..., integrándose por defecto con Quartz, Velocity, Freemarker, Struts, Webwork2 y tienen un plugin para eclipse.

Ofrece un contenedor ligero de beans para los objetos de la capa de negocio, DAOs y repositorio de Datasources JDBC y sesiones Hibernate. Mediante un xml definimos el contexto de la aplicación, siendo una potente herramienta para manejar objetos Singleton o “factorias” que necesitan su propia configuración.

El objetivo de Spring es no ser intrusivo, aquellas aplicaciones configuradas para usar beans mediante Spring no necesitan depender de interfaces o clases de Spring pero obtienen su configuración a través de las propiedades de sus beans. Este concepto puede ser aplicado a cualquier entorno, desde una aplicación JEE a un applet.

El paquete “Core” es la parte más fundamental del framework ya que provee a éste de las características de Inversión de Control (IoC) e Inyección de dependencias (ID). El concepto básico dentro del “Core” es el “BeanFactory”, el cual provee una sofisticada implementación del patrón "Factory”, que elimina la necesidad generalizada de “Singletons” y nos permite desacoplar la configuración y especificación de las dependencias de nuestra lógica de programación.

¿Cuando usar Spring?

Con los bloques descritos en la sección anterior uno puede usar Spring en una multitud de escenarios, desde applets hasta aplicaciones empresariales complejas usando la funcionalidad de Spring para el manejo transaccional y el framework Web.

  • Aplicación Web Típica. Una aplicación web típica usa gran parte de las características de Spring. Por medio de los TransactionProxyFactoryBeans la aplicación web se vuelve totalmente transaccional, tal y como pudiera ser si se usaran las transacciones administradas por el contenedor, como lo manejan los Enterprise JavaBeans. Toda la lógica de negocio puede ser implementada usando POJOs, administrados por el contenedor de Inyección de Dependencias de Spring. Existen servicios adicionales como el envío de mails y la validación, independientes a la capa web, que te permiten escoger dónde y cuándo ejecutar las reglas de validación. Los controladores de formas te permiten integrar la capa web con el modelo de dominio, eliminando la necesidad de ActionForms o cualquier clase que transforme los parámetros HTTP en valores para el modelo de dominio.
  • Capa intermedia de Spring con un framework WEB alternativo. A veces las circuntancias actuales no te permiten cambiarte completamente a un framework diferente. Spring NO TE OBLIGA a utilizar todo lo que provee, es decir, no se trata de una solución todo o nada. Existen frontends como Webwork, Struts, Tapestry o JSF que permiten integrarse perfectamente a una capa intermedia basada en Spring, permitiéndote usar todas las características transaccionales que Spring ofrece. Lo único que necesitas es ligar tu lógica de negocios usando un ApplicationContext e integrar tu capa Web mediante un WebApplicationContext.
  • Escenario de acceso a recursos remotos. Cuando necesitas acceder a código existente vía web services, puedes utilizar las clases Hessian-, Rmi- o JaxRpcProxyFactory. Habilitar acceso remoto a aplicaciones existentes no es tan difícil.
  • EJBs - Envolviendo POJOs existentes. Spring provee una capa de acceso y una capa de abstracción para Enterprise JavaBeans, permitiéndote reutilizar POJOs existentes y envolverlos en Stateless Session Beans, para ser utilizados en aplicaciones web robustas y escalables, que puedan necesitar seguridad declarativa.

Conceptos del Framework

A continuación vamos a reseñar las características principales sobre las que se basa el framework.

¿Que es el IoC?

Spring se basa en IoC. IoC es lo que nosotros conocemos como "El Principio de Inversión de Dependencia, Inversion of Control" (IoC) o patrón Hollywood ("No nos llames, nosotros le llamaremos") y consiste en:

  • Un Contenedor que maneja objetos por ti.
  • El contenedor generalmente controla la creación de estos objetos. Por decirlo de alguna manera, el contenedor hace los “new” de las clases java para que no los realices tú.
  • El contenedor resuelve dependencias entre los objetos que contiene.

Estos puntos son suficientes y necesarios para poder hablar de una definición básica de IoC. Spring proporciona un contenedor que maneja todo lo que se hace con los objetos del IoC. Debido a la naturaleza del IoC, el contenedor más o menos ha definido el ciclo de vida de los objetos y resuelve las dependencias entre los servicios que él controla.

El principio antes expuesto tiene varios beneficios, entre los que podemos destacar:

  • Quita la responsabilidad de buscar o crear objetos dependientes, dejando estos configurables. De esta forma, las búsquedas de componentes complejas, como es el uso de JNDI, pueden ser delegadas al contenedor.
  • Reduce a cero las dependencias entre implementaciones, favoreciendo el uso de diseño de modelos de objetos basados en interfaces.
  • Permite a la aplicación ser reconfigurada sin tocar el código.
  • Estimula la escritura de componentes testeables, pues la Inversión del Control facilita el uso de pruebas unitarias.

¿Que es AOP?

La definición más simple de AOP es “una manera de eliminar código duplicado”. Java es un lenguaje orientado a objetos y permite crear aplicaciones usando una determinada jerarquía de objetos, sin embargo esto no permite una manera simple de eliminar código repetido en aquellos objetos que no pertenecen a la jerarquía. AOP permite controlar tareas.

En AOP usaremos conceptos como interceptor, que inspeccionará el código que se va a ejecutar, permitiendo, por lo tanto, realizar ciertas acciones como: escritura de trazas cuando el método es llamado, modificar los objetos devueltos o envío de notificaciones.

La Programación Orientada a Aspectos (AOP) complementa la Programación Orientada a Objetos (POO) proponiendo otra manera de pensar sobre la estructura de un programa. Mientras que la POO descompone las aplicaciones en una jerarquía de objetos, la AOP descompone los programas en aspectos (aspects) o preocupaciones (concerns). Esto permite la modularización de preocupaciones justo como el manejo de transacciones que pueden ser aplicados a múltiples objetos.

Uno de los componentes clave de Spring es el framework AOP. Los contenedores IoC de Spring (BeanFactory y ApplicationContext) no dependen de AOP, lo que implica que no necesitas usar AOP si no quieres, ya que AOP complementa el IoC de Spring para proporcionar una solución muy eficaz.

AOP se usa en Spring:

  • Para proporcionar servicios empresariales de manera declarativa, especialmente como reemplazo para los servicios declarativos de EJB. El más importante de dichos servicios es el manejo declarativo de transacciones, que esta construido sobre la abstracción de transacciones de Spring.
  • Para permitir que los usuarios implementar aspectos personalizados, complementando el uso de POO con AOP.

Algunos servicios son utilizados repetidas veces en diferentes componentes de un sistema cuya responsabilidad principal es otra. Un framework de AOP hace posible modularizar estos aspectos o servicios y aplicarlos declarativamente a los componentes que los precisen:

  • Cada aspecto se implementa en un único punto.
  • Declarativamente se especifican los métodos que el framework tiene que interceptar para aplicarles el o los aspectos que el desarrollador desea.
  • Cada componente debe preocuparse únicamente de su funcionalidad principal sin preocuparse de los servicios del sistema que precise.

Para construirlo correctamente

  • Definir un interfaz con los métodos a interceptar.
  • Implementar la interfaz.
  • Implementar un Consejo, que es una clase que interceptará la ejecución de los métodos. Hay tres formas de realizarla dependiendo de las necesidades:
    • Se implementa MethodInterceptor para realizar la operación antes y después de la invocación al método.
    • Se implementa MethodBeforeAdvice para realizar operaciones antes de la ejecución del método.
    • Se implementa AfterReturningAdvice para realizar operaciones después de la ejecución del método.
  • Configurar el archivo spring-config.xml correctamente
    • Implementaciones de la interfaz.
    • Implementación de la interceptación de método.
    • Definición del Point Cut.
<bean id="nombre" class="org.springframework.aop.support.RegexpMethodPointCutAdvisor">
<!- Patron que utilizará para aplicar el consejo>
    <property name="pattern">
      <value>*.*</value>
    </property>
<!- Referencia a un Bean que implementa un advice>
    <property name="advice">
      <ref bean="metobbdd"/>
    </property>
</bean>

Transaccionalidad en Spring

La transaccionalidad en Spring está basada en AOP. Para ello se dispone del interceptor org.springframework.transaction.interceptor.TransactionProxyFactoryBean

<bean id="GrupoDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
        <ref bean="transactionManager"/>
    </property>
    <property name="target">
        <ref bean="GrupoDAOtarget"/>
    </property>
    <property name="transactionAttributes">
        <props>
            <prop key="insert">PROPAGATION_REQUIRED, ISOLATION_DEFAULT</prop>
            <prop key="update">PROPAGATION_REQUIRED, ISOLATION_DEFAULT</prop>
            <prop key="delete">PROPAGATION_REQUIRED, ISOLATION_DEFAULT</prop>
            <prop key="find*" >PROPAGATION_SUPPORTS, ISOLATION_DEFAULT,readOnly</prop>
        </props>
    </property>           
</bean>

Tres son las propiedades que necesita TransactionProxyFactoryBean:

  • transactionAttributes: Demarca los límites de la transacción: define qué métodos son transaccionales. Define cómo colabora con otras posibles transacciones anidadas. Por ejemplo, los casos más típicos para consultas de acción:
    • PROPAGATION_REQUIRED: indica que, si no hay una transacción iniciada, inicia una.
    • PROPAGATION_REQUIRES_NEW: crea una transacción nueva, con independencia de que ya existiera una.

Los casos más típicos para las consultas de selección son:

  • PROPAGATION_SUPPORTS: se asocia a una transacción, si existe. En caso contrario se ejecuta sin transacción.
  • PROPAGATION_NEVER: Nunca se ejecuta transaccionalmente. Si existiera una, produciría una excepción.

Define el nivel de aislamiento de los datos de la transacción respecto de otros usuarios.

  • target: Es el bean sobre el cual se quiere controlar su transaccionalidad. Típicamente estos serán instancias DAO o servicios. Es necesario que estén definidos dentro del contenedor para que puedan ser referenciados.
  • transactionManager: Manejador de transacciones. Dos tipos de transacciones, locales y globales. Es posible cambiar el manejador de Transacciones de local a global, sin más que cambiar la configuración de Spring.
    • Locales: Transacciones con un único origen de datos. Se basan en que todos los elementos de una unidad transaccional comparten la misma conexión
    • Globales o distribuidas: Basadas en JTA, están son transacciones entre varios EIS, por ejemplo dos bases de datos, o una base de datos y un CICS. Se requiere un motor transaccional, tal como en los motores de EJBs.

Seguridad en Spring

Spring Security, antes conocido como Acegi, es un marco de seguridad que nos proporciona la posibilidad de crear una capa de seguridad declarativa en nuestras aplicaciones basadas en Spring. Spring Security va más allá que la especificación JEE 5, proporcionando un marco más completo y, lo que es más importante, totalmente independiente del entorno en el que se despliega la aplicación. Las condiciones de seguridad viajan en el artefacto a desplegar, lo que hace más fácil tanto el desarrollo como la migración o el mantenimiento de nuestro sistema. Las condiciones y la infraestructura son las mismas, despleguemos en un Jboss, en un Tomcat o en un Glassfish, aportando un poco más de independencia del entorno de despliegue del que se puede conseguir con JEE5 o JAAS. Spring Security aporta una solución completa para los dos principales requisitos de seguridad, la autenticación y la autorización, y lo hace tanto a nivel de peticiones web, como a la hora de las llamadas a métodos. Para conseguir sus misiones Spring Security hace uso de las posibilidades de dependencia inyectada de Spring, las capacidades de AOP, para la seguridad en la llamada a los métodos, y el uso de los filtros, para la seguridad en las peticiones web. En definitiva,  usa lo mejor de spring y lo mejor de JEE5. De hecho, proporciona un puente entre los dos mundos al permitir declarar los filtros y las dependencias de estos, como componentes de Spring, e inyectarlos en nuestra aplicación como un componente más.

El uso de filtros para la seguridad no deja de ser una decisión relevante, pues al ser un componente estándar de cualquier motor de servlets, o solución basada en JEE5, hace posible integrar la solución de Spring Security con cualquier marco de desarrollo de aplicaciones web basado en java, bien sea JSF, Struts, Spring MVC, Wicket, etc. Aunque Spring Security nos viene dotado de serie de las clases necesarias para identificar a los usuarios de nuestra aplicación de las maneras más comunes en internet, pudiera darse el caso de que alguna aplicación requiera un sistema no presente en la distribución. Adaptarse a esa situación es muy fácil con Spring Security, tiene una API bastante simple y general que nos permite desarrollar fácilmente un sistema para nuestro nuevo requerimiento y adaptarlo a Spring Security con tan solo respetar unas normas generarles. Obviamente, para estos casos habrá que saber un poco de la arquitectura de Spring Security y cómo funciona internamente para poder adaptar nuestra creación herramienta.

El hecho de que tenga un API tan simple, el hecho de que use filtros, el hecho de emplear Spring, el hecho de utilizar AOP, etc, permite a nuestro código, el que verdaderamente tenemos que crear nosotros para la aplicación que tenemos entre manos, estar libre de todo rastro de condiciones de seguridad, la simplicidad de Spring Security se traslada a nuestra aplicación, gracias a poder hacer uso de la seguridad declarativa. Y esto tiene otra ventaja añadida, y es que es factible aplicar Spring Security a aplicaciones que fueron creadas hace tiempo, añadiéndole una capa de seguridad de la que carecían cuando fueron desarrolladas.

A modo de mostrar un poco todo su arsenal, ahí van algunos de los sistemas de identificación para los que Spring Security proporciona de serie la posibilidad de usar:

  • HTTP BASIC
  • HTTP Digest
  • HTTP X.509
  • LDAP
  • Formularios HTML
  • Base de datos.
  • OpenID
  • JA-SIG Central Authentication
  • Computer Associates Siteminder
  • JAAS
  • Soluciones para contenedores (Jboss, Tomcat, Jetty)
  • Java Open Source Single Sign On
  • Autentificación anónima.

Inyección de dependencias

Spring provee tres tipos de inyección de dependencias: inyección por constructor, por setter y por método. Normalmente sólo utilizamos las dos primeras.

<bean id="invasorService" class="MADEJA.spring.InvasorService">
       <constructor-arg ref="invasorDAO"/>
</bean>
 <bean id="robotService" class="MADEJA.spring.RobotService">
        <property name="robotDAO" ref="robotDAO">
</bean>

En este ejemplo, el bean invasorService usa inyección por constructor, mientras que el bean robotService usa inyección por setter. La inyección de dependencias por constructor garantiza que el bean no será construido con un estado inválido, pero la inyección de dependencias por setters es mucho más flexible, especialmente cuando la clase tiene muchas propiedades y la mayoría de ellas son opcionales.

Las inyecciones de dependencias mediante Setters se pueden especificar de las siguientes formas:

  • A través de un elemento anidado property, que acepta los siguientes atributos
    • name: Nombre de la propiedad donde se desea inyectar el valor.
    • value: Para inyectar un valor constante.
    • ref: Para inyectar otro bean a partir de su nombre.
  • Con sintaxis abreviada (utilizando el espacio de nombres p) a través de los atributos
    • p:nombrePropiedad: Para inyectar un valor constante en la propiedad indicada.
    • p:nombrePropiedad-ref: Para inyectar otro bean a partir de su nombre en la propiedad indicada.
  • El bean se crea a partir de su constructor vacío y a continuación se invocan los métodos set con los valores adecuados.

Vamos a plasmar las principales funcionalidades de la inyección de dependencias.

Descripciones en los encabezados de los ficheros de configuración

Los ficheros de configuración pueden contener una cabecera en la que se indique una descripción de los beans que se utilizan. Un ejemplo de dicha descripción es el siguiente:

<beans>
    <description>
        Este archivo define los Invasores que atacarán los disintos planetas. Depende de RobotsServices.xml, el cual provee los
        servicios de los robots que cada invasor tiene asignado....
    </description> 
 ...
</beans>

Paso de Parámetros

Spring permite utilizar índices (que comienzan en cero) para resolver el problema de ambigüedad cuando un constructor tiene más de un argumento del mismo tipo, o cuando se utiliza el atributo value para asignar el valor. Por ejemplo, en vez de:

<bean id="InvasorService"
        class="com.dosideas.spring.InvazorService">
        <constructor-arg index="0" value="Zim"/>
        <constructor-arg index="1" value="100"/>
</bean>

es mejor utilizar el atributo type de la siguiente manera:

<bean id="invasorService"
        class="com.dosideas.spring.InvasorService">
        <constructor-arg type="java.lang.String" value="Zim"/>
        <constructor-arg type="int" value="100"/>
</bean>

Utilizar index es más sencillo, ya que codificamos menos, pero es más propenso a errores y mucho mas difícil de leer que si utilizamos type.

Lo plasmamos mediante un ejemplo.

  • La interfaz proveedor de mensaje se implementará con la clase ProveedorMensajeConfigurable. Esta clase tendrá un constructor al que se le pasará por parámetro el mensaje que queramos mostrar. El valor a dicho mensaje se lo vamos a dar en el fichero de configuración.
  • En el archivo de configuración se cambiará el bean “proveedor"

La implementación del proveedor es la siguiente:

package org.madeja.spring.ejemplo01;

/**
 *
 * @author MADEJA
 */
public class ProveedorMensajeConfigurable implements ProveedorMensaje {

    private String mensaje;
   
    public ProveedorMensajeConfigurable(String mensaje){
        this.mensaje = mensaje;
       
    }
    public String getMensaje() {
        return mensaje;
    }
   
}

El fichero de configuración será:

<?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="renderizador" class="org.madeja.spring.ejemplo01.RenderizadorMensajeSalidaEstandar">
        <property name="proveedorMensaje">
            <ref local="proveedor"/>
        </property>
    </bean>
    <bean id="proveedor" class="org.madeja.spring.ejemplo01.ProveedorMensajeConfigurable">
        <constructor-arg>
            <value>Mensaje pasado como argumento</value>
        </constructor-arg>
    </bean>
</beans>

Al realizar estos cambios y ejecutar la aplicación nos debe mostrar como resultado: Mensaje pasado como argumento.

En este ejemplo hemos visto cómo pasar los valores de las propiedades en el fichero de configuración. Las propiedades que admite Spring son:

  • Valores primitivos.
  • String.
  • Clases envoltura de los valores primitivos.
  • Otros beans.
  • Colecciones: List, Set, Map y Properties.
  • Null.

Pseudo-herencia entre beans

Spring ofrece un mecanismo de pseudo-herencia que reduce la duplicación de información en los archivos de configuración. Una definición de un bean hijo puede heredar la información de configuración de sus padres, los cuales sirven como una plantilla para los beans hijos. Todo lo que se necesita hacer es especificar la propiedad abstract=true en el bean padre y referenciar a dicho bean desde los beans hijos. Por ejemplo:

<bean id="abstractInvasorService" abstract="true"
        class="MADEJA.spring.AbstractInvasorService">
        <property name="nombreInvasor" value="Zim"/>
</bean>
<bean id="InvasorService"
        parent="abstractInvasorService"
        class="MADEJA.spring.InvasorService">
        <property name="robotAsignado" value="Gir"/>
</bean>

El bean InvasorService hereda el valor Zim para la propiedad nombreInvasor del bean abstractInvasorService.

Una aclaración: Si no se especifica el nombre de una clase en un factory method en la definición de un bean, este bean es implícitamente abstracto.

Integración de archivos de configuración mediante ApplicationContext

Al igual que el import en los scripts de Ant, el import en Spring es conveniente para unir archivos modularizados de configuración. Por ejemplo:

<beans>
        <import resource="InvasorServices.xml"/>
        <import resource="RobotsServices.xml"/>
         <bean id="PlanetaObjetivoService"
                 class="MADEJA.spring.PlanetaObjetivoService"/>
<beans>

En vez de unirlos dentro del XML utilizando imports, es mucho más flexible configurarlo a través del ApplicationContext. Utilizando ApplicationContext también hace que nuestra configuración XML sea más facil de manejar. Se le puede pasar como argumento al constructor de ApplicationContext una lista de archivos de configuración. Nuestro ejemplo anterior quedaría:

String[] serviceResources =  {"PlanetaServices.xml", "InvasorServices.xml", "RobotServices.xml"};
ApplicationContext orderServiceContext = new ClassPathXmlApplicationContext(serviceResources);

Autowiring

La inyección de dependencias de Spring dispone de una característica muy potente llamada autowiring. Ésta permite que las propiedades sean inyectadas de forma automática. La forma de utilizarla es mediante el atributo autowire del elemento bean. Los valores que puede tomar son los siguientes:

  • byName: Identifica a los beans a través de su propiedad “name”.
  • byType: Identifica a los beans a través del tipo.
  • constructor: Encaja con los tipos de argumentos del constructor.
  • autodetect: Primero lo intenta por constructor y luego por tipo.

En este ejemplo se mostrará el uso de los cuatro tipos de autowiring. Creamos una clase Garaje que contendrá tres atributos, dos de la clase Coche y uno de la clase Moto. En el archivo de configuración se crearán cuatro beans de la clase Garaje cada uno con un valor distinto para el atributo autowire. En la clase principal instanciaremos los cuatro beans a través de la factoría.

Implementación de la clases

package org.javacenter.spring.ejemplo03;

/**
 * @author MADEJA
 */
public class Coche {

}
/**
 * @author MADEJA
 */
public class Moto {

}

/**
 * @author MADEJA
 */
public class Garaje {  
    private Coche coche;
    private Coche miCoche;  
    private Moto miMoto;
  
    public Garaje() {
        System.out.println("Llamada al Constructor: Garaje()");
    }  
    public Garaje(Coche coche) {
        System.out.println("Llamada al Constructor: Garaje(Coche coche)");
        this.coche = coche;
    }  
    public Garaje(Coche miCoche, Moto miMoto) {
        System.out.println("Llamada al Constructor: Garaje(Coche miCoche, Moto miMoto)");
        this.miCoche = miCoche;
        this.miMoto = miMoto;
    }
    public void setCoche(Coche coche) {
        System.out.println("Llamada al método: setCoche(Coche coche)");
        this.coche = coche;
    }
    public void setMiCoche(Coche miCoche) {
        System.out.println("Llamada al método: setMiCoche(Coche miCoche)");
        this.miCoche = miCoche;
    }
    public void setMiMoto(Moto miMoto) {
        System.out.println("Llamada al método: setMiMoto(Moto miMoto)");
        this.miMoto = miMoto;
    }
}

La clase principal

package org.madeja.spring.ejemplo03;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
/**
* @author Madeja
*/

public class Ejemplo03 {
    public static void main(String[] args) {
        BeanFactory factory = new XmlBeanFactory(new FileSystemResource("ejemplo03-beans.xml"));
        Garaje garaje = null;
        System.out.println("----------------------------");
        System.out.println("Inyección automática por nombre");
        garaje = (Garaje) factory.getBean("garajePorNombre");
         System.out.println("----------------------------");
        System.out.println("Inyección automática por tipo");
        garaje = (Garaje) factory.getBean("garajePorTipo");
        System.out.println("----------------------------");
        System.out.println("Inyección automática por Constructor");
        garaje = (Garaje) factory.getBean("garajeConstructor");
        System.out.println("----------------------------")
                System.out.println("Inyección automática por autodetección");
        garaje = (Garaje) factory.getBean("garajeAutodetecta");
    }
}

Fichero de configuración:

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="coche" class="org.javacenter.spring.ejemplo03.Coche"/>
    <bean id="moto" class="org.javacenter.spring.ejemplo03.Moto"/>
    <bean id="garajePorNombre" autowire="byName" class="org.javacenter.spring.ejemplo03.Garaje"/>
    <bean id="garajePorTipo" autowire="byType" class="org.javacenter.spring.ejemplo03.Garaje"/>
    <bean id="garajeConstructor" autowire="constructor" class="org.javacenter.spring.ejemplo03.Garaje"/>
    <bean id="garajeAutodetecta" autowire="autodetect" class="org.javacenter.spring.ejemplo03.Garaje"/>
</beans>

La salida del programa es la siguiente:

----------------------------
Inyección automática por nombre
Llamada al Constructor: Garaje()
Llamada al método: setCoche(Coche coche)
----------------------------
Inyección automática por tipo
Llamada al Constructor: Garaje()
Llamada al método: setCoche(Coche coche)
Llamada al método: setMiCoche(Coche miCoche)
Llamada al método: setMiMoto(Moto miMoto)
----------------------------
Inyección automática por Constructor
Llamada al Constructor: Garaje(Coche miCoche, Moto miMoto)
----------------------------
Inyección automática por autodetección
Llamada al Constructor: Garaje()
Llamada al método: setCoche(Coche coche)
Llamada al método: setMiCoche(Coche miCoche)
Llamada al método: setMiMoto(Moto miMoto)

ApplicationContext

El ApplicationContext es una extensión de BeanFactory. Soporta una infraestructura que aporta muchas características, como por ejemplo transacciones y AOP. Las características que añade son las siguientes:

  • Interfaces adicionales para el ciclo de vida.
  • Propagación de eventos para los beans que implementen la interfaz ApplicationListener.
  • MessageSource, que proporciona acceso a los mensajes de internacionalización.
  • Acceso a los recursos como URLs y ficheros.
  • Carga de múltiples contextos que permiten que sean enfocados a una capa particular, por ejemplo la capa web de una aplicación.

Aunque es posible crear de forma programática un ApplicationContext lo normal es que se cree automáticamente cuando iniciamos la aplicación. Esto se consigue con la ayuda de clases de soporte como ContextLoader.

Interfaces del ciclo de vida

  • Interfaz ApplicationContextAware: Los beans que implementen esta interfaz tendrán una referencia al contexto gracias al método de la interfaz setApplicationContext() que será llamado en la creación del bean. A continuación se muestra un ejemplo de implementación de esta interfaz:
public class Publisher implements ApplicationContextAware {
    private ApplicationContext ctx;
   
    public void setApplicationContext(
        ApplicationContext applicationContext)
        throws BeansException {
        this.ctx = applicationContext;
    }
    // Código que usa ApplicationContext
}
  • Interfaz BeanPostProcessor: Implementando esta interfaz el bean será avisado antes y después de que se instancie otro bean en la factoría. Un posible ejemplo sería el siguiente:
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;

public class PostProceso implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException {
        System.out.println("El Bean '" + beanName + "' se esta instanciando ");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException {
         System.out.println("Bean '" + beanName + "' creado: " + bean.toString());
         return bean;
     }
}

Si registramos este bean en un ApplicationContext, los métodos serán llamados antes y después de inicializar cada bean del ApplicationContext

Propagación de eventos

El manejo de eventos se proporciona a través de la clase ApplicationEvent y la interfaz ApplicationListener. Cuando un bean que implementa la interfaz es desplegado en el contexto, será notificado cada vez que se publique un ApplicationEvent. Básicamente, éste es el patrón estándar de diseño Observador. Existen tres eventos preconstruidos:

  • ContextRefreshEvent: cuando se inicializa o refresca el ApplicationContext.
  • ContextClosedEvent: cuando se cierra el ApplicationContext.
  • RequestHandleEvent: un evento web que avisa que se ha servido una petición HTTP

Recursos

A través del contexto podemos acceder a recursos de bajo nivel que serán envueltos con la interfaz Resource. Una vez obtenido el recurso podemos acceder a la información mediante métodos que varían en función del tipo de recurso obtenido. La forma de obtener el recurso es la siguiente:

  • Resource x = contexto.getResource(String localización);

Los formatos soportados son:

  • URLs completas (“file:C:/texto.txt”).
  • URLs relativas al classpath (“classpath:texto.txt”).
  • Rutas relativas (“WEB-INF/text.txt”).

PropertyPlaceholderConfigurer

Permite importar valores de propiedades en la definición de un BeanFactory. Estos valores serán almacenados en un fichero con formato Java Properties. Esto resulta muy útil para personalizar propiedades específicas del entorno, como por ejemplo URLs de bases de datos, nombres de usuarios y contraseñas, evitando modificar el fichero de configuración XML. La forma de hacerlo sería la siguiente:

Creamos un fichero de propiedades con los pares clave/valor:

#cuentas.properties

usuario = admin
password = admin

Importamos el fichero de propiedades en el fichero de configuración xml a través de la clase PropertyPlaceholderConfigurer

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="cuentas.properties"/>
</bean>

Comprobación de dependencias

Se usa para comprobar las dependencias no resueltas de un bean desplegado en un contenedor. Se refiere a las propiedades JavaBeans del bean que, o bien no tiene especificados sus valores actuales en la definición o son proporcionados automáticamente por la característica autowiring. Esta característica es útil para asegurarnos de que todas las propiedades (o todas las de un cierto tipo) están definidas en un bean. Existen los siguientes tipos de comprobación:

  • none: no se realiza comprobación de dependencias.
  • simple: la comprobación de dependencias se realiza para tipos primitivos y colecciones (todo excepto colaboradores).
  • object: la comprobación de dependencias se realiza sólo para los colaboradores.
  • all: se realiza para todo.

Para activar la comprobación de dependencias hay que añadir el atributo dependency-check en el bean.

<bean id="invasorService"
        class="MADEJA.spring.InvasorService"
        dependency-check="objects">
        <property name="nombreInvasor" value="Zim"/>
        <constructor-arg ref="invasorDAO"/>
</bean>

En este ejemplo, el contendedor se asegurará que las propiedades de InvasorService no sean primitivas o que las colecciones estén asignadas.

Singleton

Cuando un bean es singleton, sólo se gestiona una misma instancia compartida del bean. De esta forma, para todas las peticiones del bean el contenedor de Spring nos devolverá la misma instancia. Este es el comportamiento por defecto en Spring. Esta característica se establece mediante el atributo singleton del elemento .

PropertyEditor

Un PropertyEditor es una clase que convierte un valor de propiedad de String a su tipo nativo y viceversa. Spring viene con siete implementaciones preconstruidas de PropertyEditor, que son registradas con el BeanFactory. Éstas son:

  • ClassEditor
  • FileEditor
  • LocaleEditor
  • PropertiesEditor
  • URLEditor

Su uso no requiere de codificación adicional, simplemente especificamos su valor en el fichero de configuración.

Programación orientada a aspectos

La Programación Orientada a Aspectos (AOP) es un paradigma relativamente nuevo de programación. Podemos verlo como una extensión de la Programación Orientada a Objetos a la que se le añade un nivel más de encapsulación.

Cuando el diseñador va a realizar algo nuevo, define una serie de requisitos que deberá cumplir el sistema propuesto. De aquí surge un concepto importante que acompaña a la AOP denominado concern (traducido por requisito).

La POO proporciona paquetes, clases y métodos que ayudan al programador a encapsular estos requisitos en entidades separadas. Sin embargo hay ciertos requisitos que están compartidos por todo o parte del sistema y que no soportan esta encapsulación. De aquí surge el principal concepto que define la AOP: crosscutting concern o requisitos transversales. Por otro lado tenemos los requisitos que soportan la encapsulación de la POO denominados core concerns o requisitos centrales.

Con frecuencia la implementación produce lo que se conoce como código disperso y código enredado (scattering y tangling).

  • Código disperso: Hablamos de código disperso cuando una misma cuestión es implementada en distintos módulos. Podemos dividirlo en dos categorías: bloques de código duplicado y bloques de código complementarios.
  • Código enredado: Podemos decir que estamos ante un código enredado cuando un módulo es implementado de forma que maneja varios concerns simultáneamente además de cumplir con su función específica.

En la AOP aparecen una serie de conceptos que conviene tener claro. Estos son:

Puntos de Unión (Join Points)

Los puntos de unión son puntos bien definidos durante la ejecución de la aplicación. Además, en estos puntos podemos insertar lógica adicional mediante aspectos. Algunos ejemplos de puntos de unión son:

  • Invocación de un método
  • Inicialización de una clase
  • Inicialización de un objeto

Advice

Los advice hacen referencia a la porción de código que se ejecuta en un punto de unión. Existen tres tipos de advice:

  • Before Advice: Se ejecuta antes que el punto de unión.
  • After Advice: Se ejecuta después que el punto de unión.
  • Around Advice: Rodea la ejecución del punto de unión.

Puntos de Corte

Los puntos de corte no son más que uno o más puntos de unión que utilizamos para ejecutar algún consejo (advices). Mediante los puntos de corte podemos tener un control más fino sobre la aplicación. Un punto de corte típico es la colección de las invocaciones a métodos dentro de una clase particular.

Los puntos de corte son la parte de la AOP que más varía con respecto a la POO y se construyen con un lenguaje especial mediante el cual podemos crear puntos de corte a partir de otros puntos de corte formando relaciones complejas.

Aspectos

Un aspecto es la combinación de advices y puntos de corte. La forma del mismo depende del framework de aspectos que utilicemos.

Tejedor (Weaver) y Tejer (Weaving)

En la AOP se dice tejer a la acción de incrustar los advice en los puntos de corte especificados dentro de la aplicación. El agente que realiza esta tarea se denomina Tejedor. Existen dos tipos de tejedores:

  • En tiempo de compilación.
  • En tiempo de ejecución.

Objetivo (target)

Se denomina objetivo al objeto cuyo flujo de ejecución se ve modificado por algún proceso de tipo AOP. Algunas veces se le denomina “objeto advised”.

Introducciones

Las introducciones son los conceptos que menos respetan las reglas de integridad de la POO. Mediante las introducciones podemos modificar la estructura de un objeto añadiéndole nuevos métodos o campos. También podemos hacer que cualquier objeto implemente una interfaz específica sin la necesidad de que la clase del objeto implemente de forma explícita dicha interfaz.

Spring AOP

Hoy en día existen varios frameworks que proporcionan AOP y que lo hacen de distinta forma. Spring soluciona la AOP mediante proxies. Cuando queremos insertar código de aspectos en una clase, tenemos que utilizar la clase ProxyFactory para crear un proxy de una instancia de dicha clase. Mediante la clase ProxyFactory especificamos los advice y las clases a las que le aplicaremos dichos advice.

Spring proporciona dos formas de integrar aspectos en nuestra aplicación. Por un lado tenemos la aproximación mediante el framework AspectJ. Este framework de AOP es el más avanzado y proporciona gran funcionalidad. La documentación oficial puede encontrarse en el siguiente enlace:

La otra forma de integrar aspectos es mediante esquemas, o lo que es lo mismo, mediante ficheros XML. Cada uno tiene sus ventajas e inconvenientes pero el motivo para elegir uno u otro reside en el gusto de cada uno. Mediante AspectJ todo se implementa mediante clases Java mientras que con esquemas la implementación recae sobre todo en XML. La documentación de este se encuentra aquí:

Características

Spring contiene muchas características que le dan una funcionalidad muy extensa; dichas características están organizadas en siete grandes módulos como se puede observar en el siguiente diagrama. Esta sección comenta someramente las características de cada módulo.

  • El paquete “Context” está construido sobre una sólida base provista por el paquete “Core”, el cual proporciona un medio de acceso a los objetos contenidos en el framework de forma tal, que recuerda en cierta medida a la manera en cómo trabaja el registro JNDI. Este paquete hereda algunas características del paquete “Beans” y añade soporte para internacionalización (I18N), propagación de eventos, carga de recursos y la transparente creación de contextos, como por ejemplo, un “Servlet Container”.
  • El paquete “DAO” provee una capa de abstracción a JDBC, eliminando la tediosa codificación propia de JDBC y el parseo de los códigos de errores específicos de cada proveedor de base de datos. Así también, este paquete proporciona mecanismos de manejo de transacciones tanto programáticamente como declarativamente, cuyo manejo no está restringido a clases que implementen algún tipo de interfaz especial, sino que también está pensado para cualquiera de nuestros POJOs.
  • El paquete “ORM” provee una capa de integración con las APIs más populares de “Mapeo Objeto-Relacional”, tales como JPA, JDO, Hibernate y iBatis. Usando este paquete nosotros podremos utilizara cualquiera de estos ORM en combinación con todas las otras características que Spring ofrece.
  • El paquete “AOP” de Spring, provee una implementación para la programación “Orientada a Aspectos” compatible con el “AOP Alliance” que nos permite definir, por ejemplo, interceptores a un método (method-interceptors) y puntos de corte (pointcuts) para desacoplar limpiamente algunas funcionalidades implementadas en el código que lógicamente deberían conversar por separado.
  • El paquete “Web” de Spring provee características de integración orientadas a la Web, tales como funcionalidades para la carga de archivos, la inicialización del contenedor IoC usando “Servlet Listeners” y un contexto de aplicación orientado a la web.
  • El paquete “MVC” de Spring, provee una implementación del patrón MVC (Moldeo-Vista-Controlador) para las aplicaciones web. Spring MVC provee una limpia separación entre el código del modelo de dominio y los formularios web, integrándose a todas las otras características que este framework entrega.

Buenas prácticas y recomendaciones de uso

Buenas prácticas en el uso de Spring

La característica más importante que hemos detectado de Spring, es que es un contenedor de Beans que puede integrarse con cualquier otro framework debido a su característica de ser no intrusivo.

Entendemos que toda clase instanciable es susceptible de estar en el contenedor, además si esa clase sigue el estándar de Java Bean tiene el sentido adicional de IoC. En el Core de Spring hay dos clases que toman una especial relevancia:

  • BeanFactory (representa la factoría de Beans)
  • ApplicationContext (usada para obtener una instancia de un Bean).

Para obtener una instancia de un Bean en nuestra aplicación:

InterfazMiBean miBean = miInstanciaApplicationContext.getBean("MiIdBean");

Pese a que Spring nos cuenta que no es intrusivo (no aparecen clases de Spring en nuestra aplicación), lo cierto es que al menos es necesario una referencia a la clase ApplicationContext para así poder invocar a nuestros Beans. Esta única dependencia a las clases de Spring la podemos subsanar envolviendo la instancia ApplicationContext en una factoría propia como la siguiente:

package es.cice.ejemplo.factoria;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import es.cice.ejemplo.general.FactoriaSpring;
import es.cice.ejemplo.exception.MiBeanException;
import es.cice.ejemplo.interfaz.InterfazMiBean;
public class MiBeanFactoria
{
        private static final Log log = LogFactory.getFactory().getInstance(MiBeanFactoria.class);
        public static InterfazMiBean create() throws MiBeanException
        {
                try{
                        return (InterfazMiBean)FactoriaSpring.getApplicationContext().getBean("MiIdBean");
                }catch(Exception e){
                        log.error(e.getMessage());
                        throw new MiBeanException(e.getMessage());
                }              
        }
}

La gestión de los Beans que participan en la instanciación de la clase ApplicationContext se definen en ficheros de configuración, xml o properties los cuales son cargados en el arranque de nuestra aplicación. Estos ficheros se configuran de la siguiente forma:

<beans>
  ...
  <bean id="MiIdBean" class="es.cice.ejemplo.beans.MiBean" />
  ...
</beans>

En esta definición, indicamos que el contenedor va a gestionar la clase "paquete.MiBean", y que se accederá a ella mediante el identificador único "MiIdBean". De aquí en adelante en cualquier página Web que programemos podemos hacer referencia a este bean sin necesidad de nada más.

A la hora de escribir el archivo de configuración podemos hacerlo de forma abreviada o extendida. Las formas abreviadas son más fáciles de leer, dado que transforma el valor de los elementos hijos en atributos del elemento padre. Por ejemplo:

<bean id="invasorService"
      class="MADEJA.spring.InvasorService">
       <property name="nombreInvasor">
          <value>Zim</value>
       </property>
       <constructor-arg>
          <ref bean="invasorDAO">
       </constructor-arg></bean>

puede ser reescrito de forma abreviada:

<bean id="InvasorService"
      class="MADEJA.spring.InvasorService">
        <property name="nombreInvasor" value="Zim"/>
        <constructor-arg ref="invasorDAO"/>
</bean>

Esta forma de abreviar nuestra configuración deja al archivo XML mucho más claro.

El ámbito de un bean se especifica a través del atributo scope de la etiqueta bean. Los posibles valores son:

  • singleton: El contenedor usa siempre la misma instancia (ya sea cuando se le pide a través de la API o cuando necesita inyectarlo).
  • prototype: Indica que el contenedor debe crear una nueva instancia del bean cada vez que se precise una.
  • request: Indica al contenedor que debe crear una instancia por cada petición http.
  • session: Indica al contenedor que debe crear una instancia asociada a la sesión http.
  • Global session: Indica al contenedor que debe crear una instancia asociada a la sesión global http.

Spring dispone adicionalmente de una propiedad singleton a nivel de definición de clases Bean, gracias a la cual se puede dejar en manos del framework que sólo haya una instancia de dicha clase en el entorno. El valor por defecto de esta propiedad en la definición de los beans es true (singleton=true), por lo que si no se especifica, Spring intenta que sólo haya una instancia de la clase definida en sus xml de configuración. Debido a esto, si no se indica que no se quiere hacer uso de esta propiedad, se corre el riesgo de un problema con clases hijas de las definidas en la configuración de Spring.

El uso de un Singleton incumple el principio de Principio de Sustitución de Liskov. Este principio establece que un cliente que usa una clase debería funcionar también con subclases suyas. Esto es importante porque si evolucionamos un diseño extendiendo el código existente, garantizamos la compatibilidad hacia atrás de las nuevas versiones.

El siguiente sería un ejemplo de una aplicación programada con tags que hace referencia al bean definido anteriormente:

<h:outputText value=”#{MiIdBean.propiedad}”/>

Podemos tener tantos ficheros ApplicationContext como queramos, sólo tenemos que indicar su ruta en nuestra factoría de Spring:

package es.cice.ejemplo.general;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FactoriaSpring {
       private static final ApplicationContext ctx=null;
       private static final Log log = LogFactory.getFactory().getInstance(FactoriaSpring.class);
       private static final String *paths = "/applicationContext1,/applicationContext2.xml"*{style}{style:type=span|background-color=#cccccc};
        public static ApplicationContext getApplicationContext(){
              if(ctx==null){
                     ctx = new ClassPathXmlApplicationContext(paths);
              }{style}
              return ctx;
        }
}

Una vez que tenemos hecho esto, sólo nos quedaría ver un ejemplo del bean, el cual es muy simple pues sólo debemos de programar los campos a los que queramos acceder desde la aplicación web:

package es.cice.ejemplo.beans;
/**
 * Bean basico para Spring.
 * @author cice
 *
 */
public class MiBean {
    /**
     * Constructor por defecto del bean.
     */
    public MiBean() {
        // TODO Auto-generated constructor stub
    }
    /**
     * Propiedad de ejemplo.
     * @return Cadena con el resultado de la propiedad.
     */
    public String getPropiedad(){
        String resultado = "realizamos el calculo de la propiedad";
       
        return resultado;
    }
}

Ejemplos

Dentro del catálogo interno de la Junta de Andalucía se encuentra el proyecto Service Desk, en el cual se hace uso de Spring. Este proyecto se encarga de la gestión de incidencias.

Configuración web.xml

Para la utilización de Spring en el proyecto, lo primero que se hace es incluir el listener encargado de recibir las peticiones a los beans de Spring.

<!--
      - Loads the root application context of this web app at startup,
      - by default from "/WEB-INF/applicationContext.xml".
        - Note that you need to fall back to Spring's ContextLoaderServlet for
        - J2EE servers that do not follow the Servlet 2.4 initialization order.
        -
      - Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
      - to access it anywhere in the web application, outside of the framework.
      -
      - The root context is the parent of all servlet-specific contexts.
      - This means that its beans are automatically available in these child contexts,
      - both for getBean(name) calls and (external) bean references.
      -->
     
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

Configuración del applicationContext.xml


Tras realizar la configuración del listener, se procede a declarar los beans necesarios con los que se pretende el uso de Spring.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   
    <!-- Bean para cargar el fichero de properties de la carpeta <jboss>/server/<configuracion>/lib -->
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>/WEB-INF/sdk_spring.properties</value>
            </list>
        </property>
    </bean>
   
    <bean id="AuthorizationServiceRMI" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <!--  <property name="serviceUrl"><value>rmi://127.0.0.1:1201/Autorizations</value></property>-->
        <property name="serviceUrl"><value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/Autorizations</value></property>
        <property name="serviceInterface"><value>es.juntadeandalucia.servicedesk.model.service.IAuthorizationsService</value></property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>
    </bean>       
    <bean id="remoteInvocationFactory" class="org.acegisecurity.context.rmi.ContextPropagatingRemoteInvocationFactory"/>   
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="IncidentServiceRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/Incidents</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IIncidentService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="ImpactManagementServiceRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/ImpactManagement</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IImpactManagementService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="ServiceCatalogServiceRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/ServiceCatalog</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IServiceCatalogService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="ConfigurationManagementRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/ConfigurationManagement</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IConfigurationManagementService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="DMCategoryManagementRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/DMCategoryManagement</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IDMCategoryManagementService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="HistoricIncidentRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/IHistoricIncident</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IHistoricIncidentService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="PublicationsRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/Publications</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.IPublicationsService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="TasksManagerRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/TasksManager</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.ITasksManagerService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="SugestionManagementRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/ISuggestionService</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.ISuggestionService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
    <!-- Bean que utiliza el Servicio RMI publicado en un servidor-->
    <bean id="SatisfactionSurveyRMI"
        class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl">
            <value>rmi://${sdk.stubRMI.host}:${sdk.stubRMI.port}/SatisfactionSurvey</value>
        </property>
        <property name="serviceInterface">
            <value>es.juntadeandalucia.servicedesk.model.service.ISatisfactionSurveyService</value>
        </property>
        <property name="refreshStubOnConnectFailure"><value>true</value></property>
        <property name="remoteInvocationFactory"><ref bean="remoteInvocationFactory"/></property>       
    </bean>
   
</beans>

Obtención de instancia de un Bean en nuestra aplicación

Como se expuso en las buenas prácticas, para tener acceso a una instancia de un bean, se utiliza la clase del core de Spring ApplicationContext. A continuación se muestra este tipo de uso en la clase ServiceLocatorImpl, donde mostramos el código necesario:

package es.juntadeandalucia.servicedesk.view.servicelocator.implementation;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import es.juntadeandalucia.servicedesk.view.util.FacesUtils;
import es.juntadeandalucia.servicedesk.model.service.IAuthorizationsService;
...
public class ServiceLocatorImpl implements IServiceLocator {
   // the Spring application context
   private ApplicationContext appContext;
   // se cachea se servicio de Autorizaciones
   private IAuthorizationsService iAuthorizationsService;
   private static final String AUTHORIZATIONS_SERVICE_BEAN_NAME = "AuthorizationServiceRMI";   
   ...
   public ServiceLocatorImpl() {
      ServletContext context = FacesUtils.getServletContext();
      this.appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
      this.iAuthorizationsService=(IAuthorizationsService)appContext.getBean(AUTHORIZATIONS_SERVICE_BEAN_NAME);
      ...
   }
   ...
   /**
    * Consultor de la instancia del servicio de autorización.
    * @return IAuthorizationService
    */
   public IAuthorizationsService getAuthorizationService() {
      return this.iAuthorizationsService;
   }
}