¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Java Spring
  3. El contenedor Spring
Extrait - Java Spring La base técnica de las aplicaciones Jakarta EE
Extractos del libro
Java Spring La base técnica de las aplicaciones Jakarta EE Volver a la página de compra del libro

El contenedor Spring

Introducción

Este capítulo presenta un uso simplificado de Spring, para que tengamos una visión general, sin perdernos en los detalles. Posteriormente, veremos aclaraciones sobre las partes que es necesario conocer para afrontar una aplicación más compleja. El ejemplo que lo ilustra ya permite experimentar con una gran parte de los problemas relacionados con el uso de este framework.

Origen

Vamos a bordar los principales componentes de Spring.

Spring es un framework que simplifica la programación. Se compone de un núcleo, Spring Core, que permite una administración sencilla de instancias de clase en memoria y librerías de clases que utilizan este núcleo.

A estas clases se las llama beans Spring. El framework proporciona un conjunto de beans preprogramados que cubren un espectro muy amplio de casos de uso, que encontramos cuando codificamos una aplicación compleja.

Son ampliables y fáciles de usar.

El núcleo del framework permite cargar un conjunto de singletons durante el arranque y facilita su acceso inyectando automáticamente su referencia (ubicación en memoria) en los objetos que los usan.

Spring permite tener un control muy fino sobre la gestión de objetos en memoria. 

Spring interactúa con muchos frameworks y otros productos. El principal interés de Spring es la instanciación y la disponibilidad automatizada de beans. Estos objetos pueden ser de dos tipos: singletons, como ya hemos mencionado, así como objetos «duplicados» llamados «prototipos».

A diferencia de lo que sucede con el objeto Prototype, el objeto Singleton es un objeto compartido del que se crea una única instancia en un mismo contenedor Spring y cuyo uso es compartido. Spring gestiona internamente una lista de singletons instanciados. Si se debe...

Los módulos fundamentales

Los beans especializados que se muestran a continuación generalmente están presentes desde la versión 0.9 de Spring y han recibido mejoras a lo largo de las versiones. Se utilizan sobre todo cuando queremos extender Spring. Los verá principalmente en los frameworks. Cuando usamos anotaciones, dejamos de ver estos objetos, pero Spring los utiliza internamente.

1. Composición de un bean

Veremos más en detalle cómo funciona un bean en la programación orientada a aspectos con Spring dedicado a AOP.

Para simplificar, un bean se puede considerar como un proxy que extiende un objeto Java. El proxy permite:

  • capturar las llamadas a los métodos del objeto para añadir comportamientos,

  • añadir nuevos métodos,

  • gestionar vínculos a los objetos a los que se hace referencia en el objeto principal,

  • posibilidad de asignar valor a las propiedades del objeto de diferentes maneras: cadenas, archivos (a través de una factory),

  • gestionar mensajes en los bundles (a través del contexto),

  • gestionar eventos entre objetos: creación, destrucción o eventos de usuario.

El bean está orientado a datos (POJO) o procesamientos, intentando separar estos aspectos en beans especializados.

Por lo tanto, contiene:

  • la clase de implementación real del bean,

  • elementos de configuración conductual del bean, singleton/prototype,

  • beans relacionados con la inyección de dependencias, etc.,

  • valores de propiedad que se establecerán durante la construcción.

Cuando queremos usar un bean Spring, añadimos un miembro de clase e indicamos a Spring que queremos utilizarlo escribiendo la variable con la interfaz correspondiente al Bean. Spring tiene diferentes estrategias para encontrar el Bean adecuado que se va a inyectar.

Un bean se identifica por su nombre y su identificador. Los identificadores pueden tener alias, pero este uso es bastante confuso. Varios beans pueden tener el mismo identificador, por lo que se indicará a Spring cuál debe tener prioridad (@Primary).

2. El singleton y el prototipo

Un singleton, que es el tipo predeterminado de beans, solo tiene una instancia de implementación dentro de un contexto, mientras que el prototipo puede tener varias.

3. Los objetos fundamentales del paquete core

Este paquete gestiona la inyección de dependencias. Utiliza un determinado número...

Configuración de los beans

Como se ha mencionado, la configuración de los beans Spring puede ser implícita o explícita. En modo implícito, Spring reconoce qué clases Java debe añadir a la lista de beans a partir del marcado en las candidatas. En modo explícito, le decimos a Spring el nombre y la ubicación exacta de los beans. El modo explícito es más seguro, pero se tarda más en configurar. Por este motivo rara vez se usa. Los beans se pueden configurar mediante archivos XML, anotaciones o directamente en Java.

Posibilidad de declarar beans

Tipo

Modo

Uso

Archivos XML

Explícito

Beanes personalizados externamente para variación por entorno.

Código Java

Implícito y explícito

Beans de configuraciones estáticas.

Anotaciones

Implícito

Beans que experimentan pocos cambios estructurales.

Lambda

Implícito

Sin proxy (abordaremos este aspecto en detalle).

Por lo tanto, por este medio podemos declarar un árbol de objetos que contenga objetos singleton y objetos prototype. También veremos que es posible tener una configuración diferente para la «run» y para las pruebas que, por ejemplo, tienen una configuración dedicada.

La configuración por XML presenta dificultades relacionadas con el uso de la configuración en formato texto. Spring debe hacer conversiones del texto al tipo de destino. Para indicar un número, lo metemos en una cadena, que posteriormente se convierte. Para indicar el nombre de una variable o argumento, también usamos texto. Los problemas solo son visibles en tiempo de ejecución, mientras que, si se configura en Java, los problemas se revelan directamente durante la fase de compilación.

Por lo tanto, primero usaremos la configuración en Java. Los ejemplos muestran todos los tipos de configuración para presentarlos.

1. Configuración mediante un archivo XML

Las aplicaciones sencillas o antiguas se configuran directamente en uno o más archivos XML, organizados de forma jerárquica. Por lo general, tenemos un archivo XML principal por contenedor Spring, junto con archivos XML periféricos.

En el siguiente ejemplo, se muestra cómo declarar un bean miServicio que coincida con la clase de implementación miPaquete.MiServicioImpl.

<Beans> 
   <Bean...

Uso de beans: inyección para setters y constructores

La aplicación dispone del bean cuando este se declara en la configuración. Entonces, podemos inyectarlo como miembro de nuestra clase.

Spring solo puede inyectar dependencias en un bean de Spring.

Los expertos dirán que, mediante la configuración de la JVM, es posible inyectar los beans donde quiera modificando el cargador de clases, pero, en un contexto de uso normal, nos limitaremos a los beans Spring.

Por lo tanto, el primer bean de nuestra aplicación se instanciará obligatoriamente por medio de una factory Spring que cargará el contexto y aplicará la configuración a ese bean. Este es el punto de partida de Spring en la aplicación.

Spring crea el objeto con el constructor predeterminado y, a continuación, llama a los setters para inyectar las referencias de los objetos que se van a inyectar. Si el constructor predeterminado no está disponible, Spring utiliza un constructor con argumentos, que también rellena las dependencias. Esta posibilidad se usa para las API externas a Spring que no tienen constructores predeterminados, como los pools de conexiones, para los que debemos pasar el datasource como argumento constructor.

Un constructor que contiene beans como argumentos permite hacer el equivalente de la anotación @Autowired en los miembros del bean. Por otro lado, es necesario tener un número limitado de argumentos en el constructor para mantener la legibilidad.

La anotación @Autowired se coloca en la variable o, preferiblemente, en el setter de la variable. Es posible especificar que la resolución se puede diferir al inicio a través del argumento required=false:

@Autowired(required=false) 

Esto permite indicar a Spring que el bean que se va a mapear puede no estar disponible durante el inicio. Por ejemplo, si durante la instanciación (carga en la memoria) de un bean se necesita un elemento que no está disponible al inicio, es posible posponer su instanciación al momento en el que se utilice por primera vez. Un bean puede necesitar que se inicie la base de datos o que ya se haya producido una conexión a ella, por ejemplo, antes de que se pueda utilizar.

En caso de que no necesitemos utilizar la carga diferida, también es posible utilizar la anotación @Inject del JSR-330.

1. Asignación mediante el constructor en XML

El elemento...

Control del ciclo de vida: construcción y destrucción

Spring permite interceptar la creación y descripción de los objetos Spring.

No es posible utilizar los beans inyectados directamente en el constructor porque, en este preciso momento, Spring aún no ha instanciado los objetos contenidos en los miembros de la clase. Del mismo modo, la llamada al método finally no es sencilla porque es el garbage collector quien lo llama y el finally está deprecated (JEP 421). Spring da la posibilidad de marcar métodos para que se llamen durante la creación y destrucción del objeto. Hay varios mecanismos.

He aquí el más reciente.

Anotación

Momento de la llamada

@PostConstruct

Después del constructor, con los beans inicializados.

@PreDestroy

Antes de la destrucción.

También es posible utilizar aspectos de la programación orientada a aspectos (AOP) para realizar acciones durante la creación y destrucción del objeto.

Antes de estas anotaciones, usamos métodos parametrizados en la configuración con los argumentos init-method y destroy-method, como en el siguiente ejemplo:

<bean id="helloWorld" 
   class="com.tutorialspoint.HelloWorld"  
   init-method="init" destroy-method="destroy"> 
   <property name="mensaje" value="Hola"/> ...

Ejemplo que ilustra los mappings estándares

Este ejemplo describe, paso a paso, la creación de un proyecto sencillo. Está presente en los ejemplos que se pueden descargar en la página Información. En primer momento, este capítulo puede parecer un poco complejo para los principiantes, pero se puede utilizar para experimentar.

1. El Proyecto Maven

  • Cree un proyecto vacío de Maven con el siguiente arquetipo:

mvn archetype:generate -DgroupId=fr.eni.editions 
-DartifactId=mappingApp -DarchetypeArtifactId=maven-archetype-quickstart 
-DinteractiveMode=false 
  • O use el Spring Initalizr para crear un proyecto vacío (https://start.spring.io/).

  • Importe el archivo Maven a Eclipse o IntelliJ IDEA (o a su herramienta de desarrollo favorita).

  • Para separar los archivos de configuración de los archivos de código, cree los directorios de origen:

  • src/main/resources

  • src/test/resources

Pondremos en estos directorios los archivos de configuración de Spring y el sistema de registro.

2. Archivo de configuración de Spring

Crearemos un archivo Spring llamado applicationContext.xml y lo colocaremos en el directorio src/main/resources/Spring/.

<?xml version="1.0" encoding="UTF-8"?> 
<beans default-lazy-init="true" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:jdbc="http://www.springframework.org/schema/jdbc" 
   xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 
     http://www.springframework.org/schema/jdbc 
http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd 
     http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.1.xsd"> ...

Spring Expression Language

Es un lenguaje de expresión ampliamente utilizado que permite variabilizar un argumento que se fijaría en una cadena, lo que es particularmente útil con argumentos de anotación.

Su sintaxis es similar a Jakarta Expression Language (Unified EL), pero ofrece posibilidades adicionales, como la invocación de métodos en un bean o en un objeto fuera de Spring.

Es posible utilizar SpEL de forma autónoma usando algunas clases de la infraestructura del núcleo, como el analizador, pero, en general, su uso es transparente cuando codificamos con Spring. SpEL está muy cerca de las especificaciones JavaBeans.

1. Uso de ExpressionParser

ExpressionParser se utiliza para evaluar una expresión.

Rara vez lo usamos directamente, pero Spring lo utiliza muy a menudo con las cadenas que le enviamos.

ExpressionParser parser = new SpelExpressionParser (); 
Expression exp = parser.parseExpression ( "'Hola a'.concat 
(' todos')"); 
String message = (String) exp.getValue (); 

Por ejemplo, aquí concatenamos las cadenas «hola a » y «todos».

Se puede acceder a los miembros y métodos de los objetos a través de una cadena de llamadas, utilizando «.».

Por ejemplo:

"'Hola a todos'.bytes.length" 

invoca ’getBytes().length’.

El método getValue tiene la firma:

public <T>...

Servidores J2EE, Java EE y Jakarta EE

1. Aspectos generales

Spring fue diseñado originalmente para evitar el uso de los EJB, que originalmente eran inmaduros. En sus primeras versiones, Spring permitía una gestión simplificada de los EJB. Incluso hoy en día, los proyectos continúan usando Spring 3 con servidores Java JEE 6, o incluso Spring 2 asociado con un servidor Java JEE 5, generalmente con un framework casero. Algunas veces se evita la migración si las modificaciones de código son menores. Encontramos en Spring 2 y 3 casi todo lo que hay en Spring 4, excepto las anotaciones. De hecho, en la medida de lo posible, Spring ha intentado llevar las evoluciones de la versión actual en las versiones anteriores. En todas sus versiones, Spring funciona muy bien en la mayoría de los servidores J2EE, Java EE y Jakarta EE (siempre que utilice la versión que corresponda al servidor empleado).

En la práctica, los «problemas» llegan con bastante rapidez. Para empezar, están las implementaciones «propietarias» de las JVM. Una JVM de IBM no tiene los mismos errores o fallos que una JVM de Oracle. Esto significa que el código no es realmente portable. También es necesario tener en cuenta el ritmo de las versiones correctivas y las dificultades de hacer que los parches estén disponibles en los diferentes entornos.

Luego están las partes personalizadas: WebSphere, WebLogic y jBoss. Estas proponen una parte común desde un punto de vista de las especificaciones, pero cada una tendrá sus sutilezas para implementarlas y, por lo tanto, será necesario conocerlas. Además, también ofrecen partes diferenciadoras que facilitarán enormemente la vida de los desarrolladores, pero los vincularán permanentemente con un proveedor de servidores. Su objetivo es vender un paquete con máquinas, licencias, etc. Estos puentes, generalmente, permiten llamar al código «Legacy» desde el código Java.

IBM ofrece un puente con sus mainframes que permiten utilizar IMS, CISC, etc., junto con Java. WebLogic ofrece un puente con Tuxedo y workflows basados en MDB (Message Driven Bean). JBoss propone innovaciones, JBoss Rules, Hibernate o pocas interconexiones propietarias. JBoss se utiliza mucho en contenedores docker con Kubernetes y OpenShift.

En función del cliente...

Puntos clave

  • El framework es configurable en Java o mediante archivos XML.

  • Preferiblemente, usaremos la configuración de Java para nuevos proyectos.

  • Los beans se inyectan gracias a los constructores o por los setters.

  • Podemos mejorar el sistema de log predeterminado.

  • Es muy fácil hacer pruebas con Spring.

  • Es posible utilizar conjuntamente Spring y EJB.