java - tutorial - spring framework vs spring boot
Acelerar el tiempo de inicio de Spring Boot (8)
Tengo una aplicación Spring Boot.
He agregado muchas dependencias (desafortunadamente, parece que las necesito todas) y el tiempo de inicio aumentó bastante.
Solo hacer un
SpringApplication.run(source, args)
lleva 10 segundos.
Si bien eso podría no ser mucho en comparación con lo que están "acostumbrados", no estoy contento de que se necesite tanto, principalmente porque interrumpe el flujo de desarrollo. La aplicación en sí es bastante pequeña en este punto, por lo que supongo que la mayor parte del tiempo está relacionada con las dependencias agregadas, no con las clases de la aplicación en sí.
Supongo que el problema es el escaneo de classpath, pero no estoy seguro de cómo:
- Confirme que ese es el problema (es decir, cómo "depurar" Spring Boot)
- Si realmente es la causa, ¿cómo puedo limitarlo para que sea más rápido? Por ejemplo, si sé que alguna dependencia o paquete no contiene nada que Spring debería estar escaneando, ¿hay alguna forma de limitar eso?
Supongo que mejorar Spring para que tenga una inicialización de bean paralela durante el inicio aceleraría las cosas, pero esa solicitud de mejora ha estado abierta desde 2011, sin ningún progreso. Veo algunos otros esfuerzos en Spring Boot, como las mejoras de velocidad Investigate Tomcat JarScanning , pero eso es específico de Tomcat y ha sido abandonado.
Este artículo:
aunque está dirigido a pruebas de integración, sugiere usar
lazy-init=true
, sin embargo, no sé cómo aplicar esto a todos los beans en Spring Boot usando la configuración de Java. ¿Algún puntero aquí?
Cualquier (otra) sugerencia sería bienvenida.
Como se describe en esta pregunta / respuesta, creo que el mejor enfoque es, en lugar de agregar solo aquellos que cree que necesita, excluir las dependencias que sabe que no necesita.
Ver: minimizar el tiempo de inicio del arranque de primavera
En resumen:
Puede ver lo que sucede debajo de las cubiertas y habilitar el registro de depuración tan simple como especificar --debug al iniciar la aplicación desde la línea de comandos. También puede especificar debug = true en su application.properties.
Además, puede establecer el nivel de registro en application.properties tan simple como:
logging.level.org.springframework.web: DEBUG logging.level.org.hibernate: ERROR
Si detecta un módulo autoconfigurado que no desea, se puede deshabilitar. Los documentos para esto se pueden encontrar aquí: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-disabling-specific-auto-configuration
Un ejemplo se vería así:
@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
La respuesta más votada hasta el momento no es incorrecta, pero no entra en la profundidad que me gusta ver y no proporciona evidencia científica. El equipo de Spring Boot realizó un ejercicio para reducir el tiempo de inicio de Boot 2.0, y el boleto 11226 contiene mucha información útil. También hay un boleto 7939 abierto para agregar información de tiempo para evaluar la condición, pero no parece tener una ETA específica.
Dave Syer ha realizado el enfoque más útil y metódico para depurar el inicio de arranque. https://github.com/dsyer/spring-boot-startup-bench
También tuve un caso de uso similar, así que tomé el enfoque de Dave de micro-benchmarking con JMH y corrí con él.
El resultado es el proyecto de
boot-benchmark
.
Lo diseñé de modo que se pueda usar para medir el tiempo de inicio de cualquier aplicación Spring Boot, utilizando el jar ejecutable producido por la
bootJar
de
bootJar
(anteriormente denominada
bootRepackage
en Boot 1.5).
Siéntase libre de usarlo y proporcionar comentarios.
Mis hallazgos son los siguientes:
- La CPU importa. Mucho.
- Inicio de la JVM con -Xverify:none ayuda significativamente.
- Excluir las configuraciones automáticas innecesarias ayuda.
-
Dave recomendó el argumento JVM
-XX:TieredStopAtLevel=1
, pero mis pruebas no mostraron una mejora significativa con eso.
Además,
-XX:TieredStopAtLevel=1
probablemente ralentizaría su primera solicitud. - Ha habido reports de que la resolución del nombre de host es lenta, pero no encontré que fuera un problema para las aplicaciones que probé.
Me resulta extraño que nadie sugiriera estas optimizaciones antes. Aquí hay algunos consejos generales para optimizar la construcción y el inicio del proyecto al desarrollar:
-
excluir directorios de desarrollo del escáner antivirus:
- directorio de proyectos
- Construir directorio de salida (si está fuera del directorio del proyecto)
- Directorio de índices IDE (p. Ej. ~ / .IntelliJIdea2018.3)
- directorio de implementación (webapps en Tomcat)
- Actualización de hardware. use CPU y RAM más rápidos, mejor conexión a Internet (para descargar dependencias) y conexión a la base de datos, cambie a SSD. una tarjeta de video no importa.
Advertencias
- La primera opción viene por el precio de la seguridad reducida.
- La segunda opción cuesta dinero (obviamente).
Para mí, parece que estás usando una configuración de configuración incorrecta. Comience por verificar myContainer y posibles conflictos. Para determinar quién está utilizando la mayoría de los recursos, debe verificar los mapas de memoria (¡vea la cantidad de datos!) Para cada dependencia a la vez, y eso también toma mucho tiempo ... (y privilegios SUDO). Por cierto: ¿generalmente está probando el código contra las dependencias?
Si está tratando de optimizar el cambio de desarrollo para las pruebas manuales, le recomiendo el uso de devtools .
Las aplicaciones que usan spring-boot-devtools se reiniciarán automáticamente cada vez que cambien los archivos en el classpath.
Simplemente recompile, y el servidor se reiniciará (para Groovy solo necesita actualizar el archivo fuente). si está utilizando un IDE (por ejemplo, ''vscode''), puede compilar automáticamente sus archivos java, por lo que solo guardar un archivo java puede iniciar un reinicio del servidor, indirectamente, y Java se vuelve tan perfecto como Groovy a este respecto.
La belleza de este enfoque es que el reinicio incremental cortocircuita algunos de los pasos de inicio desde cero, por lo que su servicio volverá a funcionar mucho más rápido.
Desafortunadamente, esto no ayuda con los tiempos de inicio para la implementación o las pruebas unitarias automatizadas.
Spring Boot realiza muchas configuraciones automáticas que pueden no ser necesarias.
Por lo tanto, es posible que desee limitar solo la configuración automática necesaria para su aplicación.
Para ver la lista completa de configuración automática incluida, simplemente ejecute el registro de
org.springframework.boot.autoconfigure
en modo DEBUG (
logging.level.org.springframework.boot.autoconfigure=DEBUG
en
application.properties
).
Otra opción es ejecutar la aplicación de arranque de primavera con la opción
--debug
:
java -jar myproject-0.0.1-SNAPSHOT.jar --debug
Habría algo como esto en la salida:
=========================
AUTO-CONFIGURATION REPORT
=========================
Inspeccione esta lista e incluya solo las configuraciones automáticas que necesita:
@Configuration
@Import({
DispatcherServletAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
ErrorMvcAutoConfiguration.class,
HttpEncodingAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
JacksonAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
ThymeleafAutoConfiguration.class,
WebMvcAutoConfiguration.class,
WebSocketAutoConfiguration.class,
})
public class SampleWebUiApplication {
El código se copió de esta publicación de blog .
ADVERTENCIA: Si no usa Hibernate DDL para la generación automática de esquemas de base de datos y no usa caché L2, esta respuesta NO es aplicable para usted. Desplazarse hacia adelante.
Mi hallazgo es que Hibernate agrega un tiempo significativo al inicio de la aplicación. Deshabilitar la caché L2 y la inicialización de la base de datos resulta en un inicio más rápido de la aplicación Spring Boot. Deje la memoria caché activada para producción y desactívela para su entorno de desarrollo.
application.yml:
spring:
jpa:
generate-ddl: false
hibernate:
ddl-auto: none
properties:
hibernate:
cache:
use_second_level_cache: false
use_query_cache: false
Resultados de la prueba:
-
El caché L2 está activado y
ddl-auto: update
INFO 5024 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 23331 ms INFO 5024 --- [restartedMain] b.n.spring.Application : Started Application in 54.251 seconds (JVM running for 63.766)
-
El caché L2 está apagado y
ddl-auto: none
INFO 10288 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 9863 ms INFO 10288 --- [restartedMain] b.n.spring.Application : Started Application in 32.058 seconds (JVM running for 37.625)
Ahora me pregunto qué haré con todo este tiempo libre
Spring Boot 2.2.M1 ha agregado una función para admitir Lazy Initialization en Spring Boot.
Por defecto, cuando se actualiza el contexto de una aplicación, se crea cada bean en el contexto y se inyectan sus dependencias. Por el contrario, cuando una definición de bean se configura para que se inicialice perezosamente, no se creará y sus dependencias no se inyectarán hasta que se necesite.
Habilitación de la inicialización
spring.main.lazy-initialization
Establezca
spring.main.lazy-initialization
en
verdadero
Para más detalles, consulte Doc