Spring Boot
Introducción
En los últimos años, se han realizado muchas inversiones en Spring Boot para conseguir una gran sencillez en el uso del ecosistema basado en el framework Spring.
Principalmente, Spring boot es una clase SpringApplication que proporciona una forma práctica de comenzar una aplicación Spring que arranca con un método main(). En muchas situaciones, podemos delegar al método estático SpringApplication.run() la tarea de iniciar la aplicación. También es un mecanismo de autoconfiguración basado en las dependencias que están relacionadas con la aplicación. Esta aplicación puede ser standalone, un servidor, un Batch, etc.
Spring Boot es una aplicación genérica que facilita la creación de aplicaciones estándares. Podemos diseñar rápidamente aplicaciones web, batch o microservicios, basándonos en implementaciones predeterminadas que se pueden personalizar. Para aplicaciones web/web services, Spring permite, por ejemplo, crear aplicaciones independientes autónomas que pueden incorporar un contenedor Tomcat, y es posible elegir Jetty o Undertow o cualquiera de las otras implementaciones disponibles como sustituto para el contenedor de servlets interno o elegir usar un contenedor externo.
Existe un sistema de autoconfiguración que detecta automáticamente los componentes técnicos que necesita la aplicación....
Configuración de los ejemplos
Describiremos algunos ejemplos de uso.
1. Configuración de Maven para la versión 1.5 de Spring Boot
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.22.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2. Configuración Maven para la versión 2 de Spring Boot
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
[...]
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> ...
Configuración automática Spring Boot
La anotación @EnableAutoConfiguration es una composición de anotaciones @Configuration, un juego de anotaciones @Conditional que se configura en función de las anotaciones @ConditionalOnClass y @ConditionalOnMissing y que tiene en cuenta las clases encontradas en el classpath.
El servicio discovery permite cargar en runtime implementaciones de un servicio utilizando las factories. Estas últimas se cargan a través de la clase SpringFactoryLoader, que recupera una lista de factories por el nombre o tipo de la clase.
Spring Boot detecta la presencia del archivo META-INF/spring.factories, que contiene la clave:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
fr.eni.spring5.autoconfigure.LibXAutoConfiguration,
fr.eni.spring5.autoconfigure.LibXWebAutoConfiguration
Este archivo tiene su correspondencia en Spring, que contiene más de cien líneas de configuración automática: spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories. La factory tiene más de cien líneas, que contienen los mismos tipos de claves que la mencionada anteriormente.
Configuración automática de los Beans Spring
La configuración automática de Spring Boot intenta configurar la aplicación por sí sola, a partir de las dependencias de los jars añadidos. Por ejemplo...
Los starters
Los starters son dependencias que añaden configuración automática a la aplicación basada en Spring Boot. El uso de un starter permite indicar que queremos añadir una funcionalidad a la aplicación y que dejamos que el framework complete nuestra configuración. Para elegir la versión del contenedor, es suficiente con elegir el starter correcto.
A continuación, se muestra una lista de starters. Algunos se describen con más detalle en las siguientes secciones. La lista es bastante larga:
1. Starters comunes
Starter |
Utilidad |
spring-boot-starter |
Es el starter central que incluye soporte para configuración automática, el log y Yaml. Siempre estará presente. |
spring-boot-starter-aop |
Starter para la programación orientada a aspectos (AOP) con Spring AOP y AspectJ. |
spring-boot-starter-batch |
Starter para usar Spring Batch. |
spring-boot-starter-cache |
Starter para usar el soporte de caché. |
spring-boot-starter-jdbc |
Starter para usar JDBC con el pool de conexiones JDBC de Tomcat. |
spring-boot-starter- jersey |
Starter para construir aplicaciones web RESTful usando JAX-RS y Jersey como alternativa a spring-boot-starter-web. |
spring-boot-starter- security |
Starter para usar Spring Security. |
spring-boot-starter-test |
Starter para probar aplicaciones Spring Boot con JUnit, Hamcrest y Mockito. |
spring-boot-starter- validation |
Starter para utilizar Java Bean Validation con Hibernate Validator. |
spring-boot-starter-web |
Starter para crear aplicaciones web que usan Spring MVC, incluyendo las aplicaciones RESTful. Utiliza Tomcat como contenedor de servlets integrado. |
spring-boot-starter-web-services |
Starter para usar Spring Web Services. |
spring-boot-starter-websocket |
Starter para construir aplicaciones que utilizan WebSockets. |
spring-boot-starter- logging |
Starter para logger con Logback. Es un starter predeterminado. |
spring-boot-starter- tomcat |
Starter para utilizar Tomcat como contenedor de servlets integrado. Este es el contenedor de servlets predeterminado. |
spring-boot-starter-web |
Starter para la fabricación de herramientas destinadas a la producción o explotación. |
spring-boot-starter-actuator |
Starter para usar el Spring Boot’s Actuator, que proporciona una solución llave en mano para monitorizar y administrar la aplicación. Este módulo algunas veces se deshabilita porque, si está mal configurado, puede proporcionar acceso... |
Spring MVC
Spring MVC con Spring Boot utiliza los siguientes servidores:
Servidor |
Versión Servlet |
Tomcat 9 |
4.0 |
Jetty 9.4 |
3.1 |
Jetty 10.0 |
4.0 |
Undertow 2.0 |
4.0 |
Personalización de banners
Cuando la aplicación Spring Boot arranca, se muestra un banner en el log. Este banner es personalizable. Basta con añadir un archivo de texto banner.txt en el classpath o especificar su ubicación a través de banner.location en la configuración. El charset de codificación se puede especificar si no es UTF-8. También es posible utilizar una imagen: banner.gif, banner.jpg o banner.png, que se transforma en ASCII Art durante el arranque.
Podemos utilizar este sitio web para hacer ASCII Art: http://patorjk.com/software/taag
La propiedad spring.main.banner-mode se utiliza para determinar si el banner se muestra en la consola System.out (registro log) o no (en off).
Eventos de aplicación
Spring utiliza los eventos para notificar ciertas cosas, como la actualización del contexto a través del evento ContextRefreshedEvent:
@Component
public class MyListener {
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
Esto permite notificar a la clase MyListener cuando se ha actualizado el contexto y se puede utilizar para ejecutar código arbitrario cuando el contexto de la aplicación se ha iniciado completamente. Los eventos son importantes para determinar la readiness (la aplicación está preparada para recibir consultas) y la liveness (la aplicación está arrancada).
Una aplicación Spring Boot proporciona los siguientes eventos:
-
El evento ApplicationStartingEvent se envía al inicio de una ejecución, pero antes de cualquier procesamiento, excepto para registrar los listeners y starters.
-
El evento ApplicationEnvironmentPreparedEvent se envía cuando se conoce el entorno que se va a usar en el contexto, pero antes de que se cree el contexto.
-
El evento ApplicationPreparedEvent se envía justo antes de que comience la actualización, pero después de que se carguen las definiciones de los beans.
-
El evento ApplicationReadyEvent se envía después de la actualización y de que se hayan procesado todas las llamadas asociadas...
Recuperación de argumentos de la línea de comandos
Hay dos interfaces Spring Boot que permite ejecutar código justo antes de que la aplicación termine de arrancar, a través de dos interfaces: CommandLineRunner y ApplicationRunner. Estas interfaces se llaman justo antes del método run(), después de que finalice SpringApplication. Esto también puede formar parte de la fase de configuración de la aplicación.
1. CommandLineRunner
Esta interfaz permite obtener los argumentos de la línea de comandos en forma de tabla.
@SpringBootApplication
public class SpringBootWebApplication implements CommandLineRunner {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
logger.info("Application Started !!");
}
}
2. ApplicationRunner
Esta interfaz permite acceder a los argumentos a través de la interfaz ApplicationArguments, que expone varias formas de obtener esos argumentos:
-
getOptionNames(): devuelve la lista de nombres de argumentos.
-
getOptionValues(): devuelve la lista de valores de argumento.
-
getSourceArgs(): devuelve la lista de valores de argumento.
@Slf4j
public class SpringBootApplicationRunner implements ApplicationRunner...
La anotación EnableConfigurationProperties
La anotación @ConfigurationProperties permite definir una clase tipada en la que se pueden inyectar datos.
A partir de la base de la clave, Spring aplica las propiedades a los campos clave. La anotación @EnableConfigurationProperties permite activarla. Esta anotación es de tipo @Import.
Esta anotación permite importar definiciones de Beans en el log inmediatamente después de importar Beans Spring.
Configurar los logs
Spring Boot utiliza Commons Logging para todos los registros de actividad o logs, pero es posible cambiar el comportamiento predeterminado. Se proporcionan configuraciones predeterminadas para Java Util Logging, Log4J2 y Logback. En cada caso, los registros están preconfigurados para utilizar la salida de la consola, junto con la salida de archivos opcional.
Si usa starters, Logback se utilizará de forma predeterminada para los logs. También se incluye el enrutamiento Logback adecuado para garantizar que funcionen correctamente las librerías dependientes que utilizan Java Util Logging, Commons Logging, Log4J o SLF4J.
Tenemos a nuestra disposición los niveles de log clásicos FATAL (excepto para Logback), ERROR, WARN, INFO, DEBUG y TRACE.
1. Los logs de color
Si no especificamos nada, el log es monocromático, pero es posible añadir color en los logs. El sistema utilizado por defecto es Logback, que soporta colores.
Para ello, debe establecer la variable de configuración: spring.output.ansi.enabled=always.
La primera posibilidad consiste en poner un formato para el log en el archivo de configuración de la aplicación.
En el archivo de configuración:
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS}
%magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
Aquí creamos registros para verlos en color:
LOGGER.trace("Pruebas de los logs:trace");
LOGGER.debug("Pruebas de los logs:debug");
LOGGER.info("Pruebas de los logs:info");
LOGGER.warn("Pruebas de los logs:warn");
LOGGER.error("Pruebas de los logs:error");
Log mostrado:
02-03-2018 12:42:27.545 [main] TRACE
fr.eni.spring5.logs.Ex1Logs.run - Pruebas de los logs:trace
02-03-2018 12:42:27.545 [main] DEBUG
fr.eni.spring5.logs.Ex1Logs.run - Pruebas de los logs:debug
02-03-2018 12:42:27.545 [main] INFO
fr.eni.spring5.logs.Ex1Logs.run - Pruebas de los logs:info
02-03-2018 12:42:27.545 [main] WARN
fr.eni.spring5.logs.Ex1Logs.run - Pruebas de los logs:warn
02-03-2018 12:42:27.545 [main] ERROR
fr.eni.spring5.logs.Ex1Logs.run - Pruebas de los logs:error
Entonces tenemos:
-
para los bloques [main] para el thread en rosa.
-
TRACE y DEBUG en negro.
-
INFO en azul.
-
WARN en naranja.
-
ERROR en rojo.
Otra posibilidad es usar el formato con %clr: %clr(%d{yyyy-MM-dd...
Configuración automática para Spring MVC
Spring ofrece configuración automática de Spring MVC a través del starter spring-boot-starter-web.
Esto provoca que se tenga en cuenta:
-
La inclusión del bean ContentNegotiatingViewResolver y del bean BeanNameViewResolver.
-
Soporte para recursos estáticos, index.html, Favicon personalizado y WebJars.
-
Registro automático de beans Converter, GenericConverter, Formatter y MessageCodesResolver.
-
Soporte de los HttpMessageConverters y uso automático de un bean ConfigurableWebBindingInitializer.
Es posible mantener solo las funcionalidades de Spring MVC añadiendo los beans de configuración interceptores, formateadores, controladores de vista mediante la creación de nuestra propia clase @Configuration de tipo WebMvcConfigurerAdapter, pero luego no debemos usar la anotación @EnableWebMvc. Se puede proporcionar una instancia personalizada de RequestMappingHandlerMapping, RequestMappingHandlerAdapter o ExceptionHandlerExceptionResolver declarando una instancia de WebMvcRegistrationsAdapter. También podemos tomar el control completo de Spring MVC añadiendo nuestra propia clase de configuración (anotada por @Configuration) anotada con @EnableWebMvc.
Gestión de sesiones
Intentamos ser stateless porque la gestión de sesiones dificulta la agrupación en clústeres de servidores debido al uso compartido de sesiones. Por lo tanto, «emulamos» la sesión a través de una caché compartida.
En algunos casos no tenemos otra opción; estamos obligados a gestionar sesiones. Las sesiones se pueden administrar en el proyecto Spring Session, que tiene dos versiones en paralelo. El objetivo del proyecto es ofrecer una alternativa a las sesiones de contenedores Tomcat, Jetty, etc.
El módulo Spring Session gestiona las sesiones.
Existen diferencias entre las dos implementaciones.
Versión |
Información |
HttpSession |
WebSocket |
WebSession |
1.5 |
Spring 4.x |
sí |
sí |
no |
2.6 |
Spring 5.x |
sí |
sí |
sí |
En esta tabla, Spring 4 y 5 se corresponden con las versiones 1.5 y 2.6 de Spring Boot.
HttpSession (Spring): sustituye a HttpSession en un contenedor (Tomcat) de forma neutral añadiendo las siguientes funcionalidades:
-
Sesiones clusterizadas.
-
Sesión de navegadores múltiples: varios usuarios conectados en una misma instancia del navegador.
-
API RESTful: identificadores de sesión en los headers.
WebSocket: conserva la sesión HttpSession cuando recibimos mensajes WebSocket.
WebSession: permite sustituir los WebSession de una aplicación en contenedores Spring WebFlux.
Para la sesión...
Guía de migración de la versión 1.5 a la versión 2.x
En términos de migración de Spring Boot 1.5 a la versión 2.x, la documentación de Spring enumera una serie de puntos.
1. Archivos de configuración
Algunas propiedades se han cambiado entre la versión 1.5 y la versión 2.x. Se facilita un starter específico para simplificar la migración. Garantiza una compatibilidad relativa con versiones anteriores durante la migración.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
</dependency>
2. Diferentes comportamientos
Las aplicaciones Spring Boot ahora se pueden ejecutar en nuevos modos. Por esta razón, la propiedad spring.main.web-environment ahora está obsoleta y se reemplaza por spring.main.web-application-type, que proporciona más control.
3. Arranque
Es posible retrasar el arranque del servidor web hasta que se inicie la aplicación cambiando la propiedad spring.main.web-application-type=none o utilizar setWebApplicationType en SpringApplication para hacerlo mediante programación.
4. Utilizar ApplicationRunner o CommandLineRunner
En la versión 1.x, los beans ApplicationRunner y CommandLineRunner se invocan al inicio del proceso y esto ha causado problemas porque los runners no habían terminado su lanzamiento....
Descripción avanzada de Spring Boot
En este apartado se describe cómo iniciar un programa Spring Boot. Sirve para desmitificar una vez más la aparente «magia» del sistema que, en realidad, es el resultado de un trabajo interesante y concienzudo. Spring utiliza los mecanismos de Spring Boot que pone a nuestra disposición.
Las fuentes de Spring Boot se pueden ver en https://github.com/spring-projects/spring-boot. Podemos estudiar el comportamiento de Spring Boot durante el arranque a partir de estas fuentes. Una aplicación Spring Boot se caracteriza por dos elementos: la anotación @SpringBootConfiguration y el método estático RUN dentro de un programa Java estándar:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
La anotación @SpringBootApplication es una composición de las anotaciones @SpringBootConfiguration, @EnableAutoConfiguration y @ComponentScan con sus atributos predeterminados.
Como hemos visto, la anotación @SpringBootConfiguration es un alias para la anotación @Configuration y la anotación @EnableAutoConfiguration indica que tenemos la configuración incorporada o incrustada en el código. La anotación @ComponentScan indica que el paquete que contiene la clase principal sirve como...
Cargar el BootstrapContext
Spring Boot comienza inicializando el BootstrapContext, que es un minicontexto Spring temporal depurado para la fase de inicialización. El BootstrapContext se introdujo con Spring Boot en su versión 2.4 para facilitar la implementación de los módulos Spring Cloud. Permite que el framework prepare el contexto de la aplicación. Este contexto se basa en dos interfaces: BootstrapRegistry, que administra las escrituras en el contexto, y BootstrapContext, que administra la parte de la lectura.
BootstrapRegistry: registra la clase en el contexto usando el método register.
BootstrapContext: carga la clase en el contexto usando el método get(Class <T> type).
Este contexto es más sencillo porque permite asociar una clase solo con un tipo.
Ejemplo de utilización:
//Escritura en el contexto:
bootstrapContext.register(MiClase.class,
InstanceSupplier.from(MiClase::new).withScope(Scope.SINGLETON)) ;
Lectura en el contexto:
Una vez que ha arrancado Spring, este llama al addCloseListener del bootstrap context para guardar los beans en el contexto real Spring de la aplicación.
Una vez cargado el contexto, Spring prepara al listener de inicio para controlar la parte del evento.
Configuración de los listeners
Spring Boot usa la interfaz SpringApplicationRunListener que tiene EventPublishingRunListener como implementación.
Este es el listener que va a enviar los eventos durante la fase de inicialización:
Evento |
Significado |
starting |
ApplicationStartingEvent |
environmentPrepared |
ApplicationEnvironmentPreparedEvent |
contextPrepared |
ApplicationContextInitilized+Event |
ContextLoaded |
ApplicationPreparedEvent |
started |
ApplicationStartedEvent |
running |
ApplicationReadyEvent |
failed |
ApplicationFailedEvent |
Ya hemos presentado algunos de estos eventos.
1. El starting: ApplicationStartingEvent
Es posible registrar listeners, como vimos en el capítulo sobre los listeners:
class MiListener implements ApplicationListener<ApplicationStartingEvent> {
void onApplicationEvent(ApplicationStartingEvent event {...}
}
Dado que en este preciso momento del arranque Spring aún no tiene el contexto normal de la aplicación, se basará en el BootstrapContext, que podemos alimentar de tres maneras:
-
Utilizando la carga de factories a través de la mecánica del spring.factories, con la adición de una fila a org.springframework.context.ApplicationListener.
-
Utilizando los métodos SpringApplication.addListeners(...) y SpringApplicationBuilder.listeners(...).
-
Añadiendo el listener al classpath durante el inicio: -Dcontext.listener.classes=...
La propagación de eventos se realiza en la implementación predeterminada, creando y usando un initialMulticaster en el que Spring registra todos los listeners. A continuación, hay publicación y envío (dispatch) de eventos para todos los eventos, hasta llegar al evento started, después del cual hay un giro hacia el contexto real de la aplicación...
Configuración de logs
Tenemos tres eventos:
Evento |
Acciones |
ApplicationStartingEvent |
Inicio del sistema de logs (LoggingSystem) |
ApplicationEnvironmentPreparedEvent |
Elección de los niveles de log |
ApplicationPreparedEvent |
Registro del logger en el contexto |
ApplicationStartingEvent configura el log por orden de preferencia para logback, Log4j y LogManager del JDK.
ApplicationEnvironmentPreparedEvent recupera niveles de log por paquete, como por ejemplo logging.level.root=info.
En ese momento creamos el verdadero contexto Spring.
Creación de ApplicationContext
Spring escanea todos los paquetes (con ASM) y utiliza BeanProcessors.
BeanFactoryPostProcessor utiliza ConfigurationClassPostProcessor para identificar y administrar los Beans Spring @Configuration, @Component, @Repository, @Service y @Controller.
BeanPostProcessor utiliza AutowiredAnnotationBeanPostProcessor para Autowire: @Autowired, @Value, constructores, CommonAnnotationBeanPostProcessor para JSR-250: el @Resource, @PostConstruct, PersistenceAnnotationBeanPostProcessor para JPA y el EventListenerMethodProcessor y DefaultEventListenerFactory para los @EventListener.
Preparación y refresco del contexto
Para la fase de preparación, el contexto BootstrapContext se copia de nuevo en el contexto normal y se emite el evento contextPrepared. A continuación, se cierra BootstrapContext, se añade al contexto la definición del Bean principal (que contiene el main) y se emite el evento contextLoaded.
Durante la fase de refresh, se inicializa el contexto Spring y se lanza el contenedor web (Jetty, Tomcat, etc.) sin permitir conexiones.
Los stubs de propiedades se reemplazan y se crean los beans (non lazy). A continuación, Sping indica al servidor embebido que puede aceptar conexiones y se inicia el evento ContextRefreshEvent.
En este preciso momento, el contexto Spring está cargado, pero sigue siendo la parte afectada por la autoconfiguración (anotación @EnableAutoConfiguration).
EnableAutoConfiguration
La anotación EnableAutoConfiguration es de tipo Import.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override
when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY =
"spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that
they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that
they will never be
*...
Lanzamiento de runners
Justo después de que se emita el evento started, Spring lanza los runners.
Los runners se utilizan principalmente para las aplicaciones en línea de comandos. Los runners son de dos tipos, que ya hemos presentado: el ApplicationRunner y el CommandLineRunner.
Después de ejecutar el código del run, Spring emite el evento Running.
Esto concluye el ciclo de lanzamiento de la aplicación Spring Boot.
Puntos clave
-
Spring Boot se utiliza para aplicaciones que están en producción.
-
Spring Boot reduce significativamente el código que hay que producir.
-
Spring Boot permite hacer componentes autoconfigurables.