
De un traductor: dado que Spring Framework es uno de los principales marcos en los que construimos CUBA , las noticias sobre las nuevas funciones de Spring no pasan desapercibidas. La inicialización diferida es una forma de reducir el primer tiempo de arranque de la aplicación, que en nuestra era del uso generalizado de microservicios es una métrica importante. Para aquellos que prefieren leer videos, hay una presentación de 10 minutos de Josh Long sobre el tema del artículo.
El primer lanzamiento de Spring Boot 2.2 recientemente anunciado agrega soporte para la inicialización diferida. En este artículo, analizaremos la nueva funcionalidad y explicaremos cómo habilitarla.
¿Qué significa ser perezoso?
Spring Framework ha estado apoyando la inicialización diferida desde que su código fuente se movió a git hace once años. De manera predeterminada, cuando se actualiza el contexto de la aplicación, se vuelve a crear cada bean y se implementan sus dependencias. Por el contrario, si un contenedor está configurado para una inicialización diferida, no se creará y sus dependencias no se anularán hasta que sea necesario.
Habilitación de la inicialización diferida
En cualquier versión de Spring Boot, es posible habilitar la inicialización diferida, si no le importa ensuciarse las manos con BeanFactoryPostProcessor
. Spring Boot 2.2 simplemente simplifica este proceso introduciendo una nueva propiedad: spring.main.lazy-initialization
(también hay métodos equivalentes en SpringApplication
y SpringApplicationBuilder
). Cuando esta propiedad se establece en true
, los beans de aplicación se configurarán para usar la inicialización diferida.
Los beneficios de la inicialización perezosa
La inicialización diferida puede reducir significativamente el tiempo de inicio de su aplicación, ya que en esta etapa se cargan menos clases y se crean menos contenedores. Por ejemplo, una pequeña aplicación web que usa Actuator y Spring Security generalmente comienza 2.5 segundos. Y con una inicialización diferida, este proceso lleva 2 segundos. Los valores exactos de aceleración variarán de una aplicación a otra, dependiendo de la estructura del gráfico de dependencia del bin.
Nota del traductor: ejecuté este ejemplo , escribiendo Spring Boot 2.2 en las dependencias, y el tiempo de inicio con una inicialización diferida fue de 3 segundos, y sin él 4. Creo que en aplicaciones más serias, una ganancia significativa en el tiempo de inicio debido al uso de la inicialización diferida No lo veremos. Upd: por recomendación de alek_sys, se deshabilitó la validación y actualización del esquema de la base de datos y se activó la inicialización lenta de JPA en ambos casos; resultó 2.7 y 3.7 segundos antes de Started WebApplication in...
Spring Boot DevTools proporciona una aceleración significativa del desarrollo. En lugar de reiniciar la JVM y la aplicación cada vez que cambia algo, DevTools realiza un "reinicio en caliente" de la aplicación en la misma JVM. Una ventaja significativa de este reinicio es que le da a JIT la oportunidad de optimizar el código que se ejecuta cuando se inicia la aplicación. Después de varios reinicios, el tiempo inicial de 2.5 segundos disminuye en casi un 80% a 500 ms. Con una inicialización perezosa, las cosas son aún mejores. Establecer la propiedad spring.main.lazy-initialization
muestra el tiempo de reinicio directamente en el IDE igual a 400 ms.
La otra cara de la inicialización perezosa
Como se muestra arriba, la inclusión de la inicialización diferida puede reducir seriamente el tiempo de inicio de la aplicación. Y quizás tenga un deseo irresistible de usar esto constantemente, o al menos se preguntará por qué la inicialización diferida no está habilitada de forma predeterminada. Hay varios posibles efectos negativos que se aclaran mejor de inmediato.
El hecho de que las clases no se carguen y los contenedores no se creen hasta que se necesiten puede enmascarar problemas que podrían haberse identificado anteriormente en la etapa de inicio de la aplicación. Por ejemplo, puede ser la falta de la clase requerida, desbordamiento de memoria o un error asociado con la configuración incorrecta.
En las aplicaciones web, las configuraciones diferidas pueden aumentar la latencia de las solicitudes HTTP que provocan la inicialización de bin. Esta suele ser la primera solicitud, pero puede haber efectos adicionales no deseados que afectan el equilibrio de carga o el escalado automático.
¿Está esto incluido?
Si no está seguro de cómo afecta exactamente la inicialización diferida a su aplicación o si desea comprobar que otros aspectos del marco son adecuados para usted y hacer lo que necesita, entonces será útil que utilice un depurador para esto. Al establecer un punto de interrupción en el constructor bin, puede ver en qué momento exacto se inicializa el bin. Por ejemplo, en una aplicación web escrita en Spring Boot y con la inicialización diferida habilitada, puede ver que los @Controller
marcados con la anotación @Controller
no se crean hasta la primera solicitud a DispatcerServlet
Spring MVC o DispatchHandler
Spring WebFlux.
¿Cuándo activar la inicialización diferida?
Como vimos anteriormente, la inicialización diferida ofrece mejoras notables durante el inicio de la aplicación, pero también hay inconvenientes, por lo que debe usar esta función con mucho cuidado.
Un área donde la inicialización diferida puede pagar dividendos (casi sin gastos generales) es el proceso de desarrollo de la aplicación. Mientras escribe una aplicación, el tiempo de reinicio reducido proporcionado por la inicialización diferida en combinación con DevTools puede ahorrarle mucho tiempo.
¿Dónde más puede obtener los beneficios de utilizar la inicialización diferida? Esto se encuentra en las pruebas de integración. Es posible que ya esté utilizando el corte de prueba para reducir el tiempo de ejecución al limitar el número de beans inicializados en algunos tipos de pruebas. La inicialización diferida brinda una oportunidad alternativa para lograr el mismo resultado. Si está en la posición incorrecta para cambiar la estructura de la aplicación para las pruebas de "corte", o para sus pruebas específicas no hay un "corte" adecuado, entonces la inclusión de la inicialización diferida limitará el número de contenedores a los que se usan solo en su prueba. Esto reducirá el tiempo de ejecución de la prueba, especialmente si se ejecutan en un entorno aislado durante el desarrollo.
Encienda la inicialización diferida en el último producto. Y, si decide hacerlo, hágalo con precaución. Para las aplicaciones web, el administrador de contenedores puede confiar en el punto de entrada /health
, que generalmente responde con bastante rapidez, pero tenga en cuenta que, potencialmente, las primeras llamadas pueden tardar más de lo habitual. También debe recordar el tamaño de memoria asignado a la JVM para que no encuentre desbordamiento cuando se inicializan todos los componentes.