¿Qué es Spring Framework? Características II

Dic 26 2019

Por Javier Cuervas

Esta es la segunda entrega de las características de Spring Framework. Aunque cada vez está más extendido el uso de Spring Boot como alternativa a Spring Framework por su simplicidad y ahorro de configuración, es interesante entender cómo funciona y aquí tienes algunas de las claves. 

Formas de utilizar la DI

  1. Mediante constructor
  2. Mediante método setter
  3. Mediante método cualquiera

Será necesario primero crear una Interfaz, crear una clase que implemente dicha interfaz, crear una clase que contenga un atributo con la dependencia a la interfaz, crear el constructor que reciba por parámetro la interfaz y la asigne al atributo de la clase, y finalmente indicarle a Spring que realice dicha inyección de dependencia.

Ejemplo fuertemente acoplamiento (sin DI)

 

Ejemplo bajo acoplamiento (con DI)

 

Singleton y Prototype


Spring por defecto utiliza el patrón Singleton (una única instancia del objeto) aunque podemos modificar este comportamiento y cambiarlo a Prototype (instancias diferentes mediante clonación). Para ello, le indicamos el alcance en la propiedad scope del bean en concreto:

Ejemplo mediante XML:

Ejemplo mediante anotaciones:

Ciclo de vida de un Bean
 

Este sería el ciclo de vida normal o por defecto de un Bean en el contenedor de Spring:

Podemos modificar este comportamiento (gracias al AOP) para realizar acciones antes y después de la creación del Bean, apoyándonos en los métodos Init y Destroy. Para ello tendríamos que crear 2 métodos con los nombres que queramos y luego indicarle a Spring qué método corresponde a cada uno, dentro de la etiqueta del Bean correspondiente:

Ejemplo mediante anotaciones:

Uso de Anotaciones
 

Las anotaciones que se añaden a las clases, métodos, campos, etc., son etiquetas que generan metadatos a nuestras clases (conjunto de datos que describen el contenido o propósito de un objeto). Esto nos permite prescindir de los ficheros XML.

Para hacer uso de las anotaciones es necesario indicarle a Spring en el XML que debe escanear las clases en el paquete raíz en busca de anotaciones para añadir o registrar el Bean anotado:

@Component
 

Una vez añadido el component-scan en el XML, debemos anotar las clases con @Component y podemos darle un alias opcional, para que Spring sepa que se trata de una clase candidata a ser inyectada.

 

@Autowired
 

Con esta anotación podremos indicarle a Spring que el objeto o dependencia debe ser inyectado. Podemos indicarlo en el atributo, en el constructor, en el setter o cualquier otro método:

Lo que hace Spring tras Bambalinas, es buscar clases que implementen la Interfaz AdminService en este caso, para hacer la inyección. En caso de encontrar varias implementaciones debemos indicarle con @Qualifier el nombre que tenga definido la clase en el @Component:

@Scope
 

En lugar de utilizar el XML podemos anotar la clase con el ámbito o alcance que queremos utilizar (Singleton o Prototype).

Según la documentación de Spring, si utilizamos Prototype no maneja el ciclo de vida completo de un Bean. Solo lo maneja bajo el patrón Singleton.

@PostConstruct y @PreDestroy
 

En lugar de utilizar el XML podemos anotar el método para indicar los métodos Init y Destroy.

@Configuration
 

Podemos prescindir del fichero de configuración XML y usar una clase Java anotada con @Configuration

Esta clase, deberá además estar anotada con @ComponentScan para indicarle el paquete donde Spring debe buscar las clases anotadas:

 

A la hora de crear el contenedor deberemos usar la clase AnnotationConfigApplicationContext en lugar de ClassPathXmlApplicationContext.

@Bean
 

Podemos prescindir del fichero de configuración XML para pedir Beans al contenedor, usando esta anotación en los objetos de la clase de configuración anotada con @Configuration:

 

 

@PropertySource y @Value
 

Podemos prescindir del fichero de configuración XML para indicar la ruta del fichero externo de propiedades con @PropertySource y luego inyectar los valores con la referencia a la clave-valor con la anotación @Value:

 

Patrón DAO
 

Este patrón de diseño nos permite ocultar la implementación de los métodos de acceso, mostrando solo la definición de los métodos de la interfaz.

 

Spring JDBC
 

Se trata de un componente Spring para manejar bases de datos de forma más sencilla. Con Spring podemos hacer uso del proyecto de apache DBCP (Data Base Conection Pools), para apoyarnos en alguna de sus plantillas para usar los métodos de acceso a datos, por ejemplo el uso de la clase NamedParameterJdbcTemplate que permite manejar JDBC con comodines para evitar SQL inyection.

Lo primero que hay que hacer es crear un Bean de tipo DataSource con las propiedades de la conexión a base de datos:

Ejemplo
 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/springbd"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>


Autoinyectamos el template de JDBC e implementamos por ejemplo el método save():

 

Podemos usar la clase BeanPropertySqlParameterSource para simplificar el mapeo del objeto:

 

Transaccionalidad con JDBC
 

Para hacer los procesos de base de datos de forma transaccional debemos crear un Bean de tipo org.springframework.jdbc.datasource.DataSourceTransactionManager y añadir el esquema de transaccionalidad tx:

 

Luego debemos anotar los métodos que vayan a ser transaccionales con @Transactional para que las operaciones se realicen de forma atómica, todas o ninguna.

MVC
 

Para implementar el patrón de arquitectura Modelo Vista Controlador, Spring hace uso del contenedor de Servlets llamado “DispatcherServlet” que viene a ser el punto angular de todas las entradas HTTP de Spring.

Cuando se introduce una URL como http://localhost:8080/index lo que le llega al contenedor es /index. De modo que un método de tipo Handler Mapping detecta la petición, se la retorna al contenedor y el contenedor busca un método controlador anotado con @Controller, que responda a dicha petición. Éste controlador devolverá al contenedor el nombre lógico de la vista, en este caso “index”. El contenedor envía este nombre lógico a un componente de tipo View Resolver para que mediante el prefijo y sufijo configurado previamente, resuelva la ruta completa de la vista a mostrar, que será renderizada finalmente por el Visor o View:

 

 

Para crear el contenedor en Spring podemos partir de uno predefinido desde Eclipse, que será un xml que representará la clase Servlet (web.xml):

​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

A continuación deberemos añadir un View Resolver, que será un fichero de tipo Spring Bean Configuration File con las siguientes propiedades:


 

​​​​​​​

El nombre de este fichero debe coincidir con el servlet-name del web.xml seguido de un guion y la palabra servlet: “dispatcher-servlet.xml”, de este modo Spring reconocerá este tipo de ficheros.

Luego debemos de crear una clase controladora para atender las peticiones HTTP y anotarla con @Controller para que nos resuelva un nombre lógico y el contenedor haga el resto. Los métodos encargados recibir la petición y resolver el nombre lógico, deben estar anotados con @RequestMapping para definir la petición HTTP:

​​​​​​​

Para evitar conflictos de rutas que puedan surgir debido a coincidencia de nombres de mapeos en diferentes clases controladoras, podemos definir una ruta relativa en la clase que funcionará como ruta raíz de las demás rutas definidas en la clase.

 

 

JSTL
 

La tecnología JavaServer Pages Standard Tag Library (JSTL) es un componente de Java EE. Extiende las ya conocidas JavaServer Pages (JSP) proporcionando cuatro bibliotecas de etiquetas con utilidades ampliamente utilizadas en el desarrollo de páginas web dinámicas.

Podemos usar la etiqueta JSTL <c:url> para hacer referencia de forma dinámica al context path de las peticiones GET:

 

​​​​​​​

Si queremos definir atributos en el modelo y utilizarlos desde la vista, debemos hacer uso de la Interfaz Model pasada como argumento en el método controlador. Estos atributos solo serán válidos para un mismo controlador y no será visible desde otros controladores.

 

 

Y podemos ver el contenido del atributo desde la vista con SpEL (Spring Expression Language) por ejemplo:

Para hacer que un atributo persista durante toda la sesión HTTP y sea visible por todos los métodos de una misma clase controladora, podemos hacerlo de 2 formas, pasando como argumento al método controlador la clase HttpSession o bien desde la clase controladora anotándola con @SessionAttributes que acepta una lista de atributos del modelo y Spring las colocará en el HttpSession.

Para ver el resultado en la vista hacemos uso del objeto sessionScope:

​​​​​​​

 

Para limpiar todos los atributos de la sesión, debemos usar la clase SessionStatus y ejecutar el método setComplete():

 

​​​​​​​

Spring Form
 

Spring incluye una librería para mejorar el uso de formularios que nos facilitarán el trabajo. La propiedad commandName o modelAttribute del formulario, indica el nombre del atributo que definimos en el controlador. La primera vez que se muestra el formulario, la instancia de Administrador está vacía y cuando guardamos los cambios se setean los valores:

​​​​​​​

Para resolver la petición realizada tras salvar los cambios en el formulario, tendremos que crear un nuevo método handler que atienda a dicha petición definida en el action del formulario, pero además tendremos que indicarle que solo sea resuelta por método POST. Y para hacer referencia al atributo del modelo que acabamos de crear, tenemos que pasarle como argumento mediante @ModelAttribute el objeto en concreto.

Spring Form tiene una característica que nos permite mantener los datos del formulario si después de salvar los cambios regresamos hacia atrás, para de esta forma poder modificar los datos en caso de error en alguno de los campos.

Para evitar la inserción de basura al recargar varias veces la página cuando guardamos los cambios en el formulario, debemos re direccionar la petición a otra página utilizando la palabra “redirect:/admin”. Además podemos crear un atributo accesible desde otro controlador con la ayuda de la clase RedirectAttributes y su método addFlashAttribute(): si queremos capturar los parámetros que vienen en una Request, podríamos hacerlo de 2 formas, bien usando la interfaz HttpServletRequest y recuperar el valor a través del método getParameter(): o bien usar la anotación @RequestParam() como argumento del método controlador:

Si queremos recuperar un valor dinámico de la request, podemos usar como parámetro del método del controlador, la anotación @PathVariable y el nombre que le hayamos asignado en el @RequestMapping. Para dotar de modularidad y claridad a los proyectos de Spring, podemos tener diferentes archivos de configuración en lugar de un único contenedor. Para ello tenemos que indicarle a Spring cuál es contenedor raíz ContextLoaderListener que atenderá a todos los Bean Configuration File y el lugar donde se alojarán estos ficheros de configuración:

​​​​​​​

(Continuará...)

Javier Cuervas


Comparte este artículo

Utilizamos cookies propias y de terceros para ofrecerte una mejor experiencia y servicio, dentro de nuestra Web de acuerdo a tus hábitos de navegación. Si continúas navegando, consideramos que aceptas expresamente su utilización. Puedes obtener más información de cómo gestionar y configurar las cookies en nuestra Política de Cookies.

×

Preferencias de Cookies


Cookies esenciales
Cookies funcionales
Cookies de análisis
Cookies de marketing