Problemas de rendimiento de Spring startup


Estoy tratando de integrar Spring en una aplicación bastante grande con miles de clases, y estoy experimentando grandes retrasos al iniciar mi contenedor debido al escaneo de componentes.

Ya he reducido el número de directorios especificados en el "paquete base", al mínimo para reducir el tiempo perdido en el escaneo de directorios irrelevantes, pero la parte de escaneo de ruta de clase de la inicialización todavía toma alrededor de 1-2 minutos.

Entonces, ¿hay una manera de optimizar el escaneo proceso ? He pensado en almacenar la ruta de las clases candidatas en un archivo y hacer que el contenedor las obtenga del archivo en lugar de escanear la ruta de la clase con cada inicio, pero realmente no sé por dónde comenzar o si eso es posible.

Cualquier consejo es muy apreciado. Gracias de antemano.

Editar : Cargando las definiciones de bean forman un archivo xml autogenerado, redujo el tiempo de arranque de Spring a 9~10 segundos, lo que confirma que la api de reflexión utilizada por Spring para la clase de componentes, el escaneo de rutas es la principal fuente de retrasos en el inicio.
En cuanto a la generación del archivo xml aquí está el código, ya que podría ser útil para alguien con los mismos problemas.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;


public class ConfigurationWriter {

    public ArrayList<String> beanDefinitions = new ArrayList<String>();

    public ConfigurationWriter() {

        // the context loaded with old fashioned way (classpath scanning)
        ApplicationContext context = SpringContainerServiceImpl.getInstance().getContext();
        String[] tab = context.getBeanDefinitionNames();
        for (int i = 0; i < tab.length - 6; i++) {
            Class clazz = context.getType(tab[i]);
            String scope = context.isPrototype(tab[i]) ? "prototype" : "singleton";
            String s = "<bean id=\"" + tab[i] + "\" class=\"" + clazz.getName() + "\" scope=\"" + scope + "\"/>";
            beanDefinitions.add(s);
        }
        // Collections.addAll(beanDefinitions, tab);

    }

    @SuppressWarnings("restriction")
    public void generateConfiguration() throws FileNotFoundException {
        File xmlConfig = new File("D:\\dev\\svn\\...\\...\\src\\test\\resources\\springBoost.xml");
        PrintWriter printer = new PrintWriter(xmlConfig);

        generateHeader(printer);

        generateCorpse(printer);

        generateTail(printer);

        printer.checkError();

    }

    @SuppressWarnings("restriction")
    private void generateCorpse(PrintWriter printer) {

        for (String beanPath : beanDefinitions) {
            printer.println(beanPath);
        }

    }

    @SuppressWarnings("restriction")
    private void generateHeader(PrintWriter printer) {
        printer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        printer.println("<beans xmlns=\"http://www.springframework.org/schema/beans\"");
        printer.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
        printer.println("xmlns:context=\"http://www.springframework.org/schema/context\"");
        printer.println("xsi:schemaLocation=\"");
        printer.println("http://www.springframework.org/schema/mvc");
        printer.println("http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd");
        printer.println("http://www.springframework.org/schema/beans");
        printer.println("http://www.springframework.org/schema/beans/spring-beans-3.0.xsd");
        printer.println("http://www.springframework.org/schema/context");
        printer.println("http://www.springframework.org/schema/context/spring-context-3.0.xsd\"");
        printer.println("default-lazy-init=\"true\">");
    }

    @SuppressWarnings("restriction")
    private void generateTail(PrintWriter printer) {
        // printer.println("<bean class=\"com.xxx.frmwrk.spring.processors.xxxBeanFactoryPostProcessor\"/>");
        printer.println("<bean class=\"com.xxx.frmwrk.spring.processors.xxxPostProcessor\"/>");
        printer.println("</beans>");
    }

}
Author: Mehdi, 2011-05-10

6 answers

Pregunta: ¿Cuántas (en %) de las clases en los directorios son Spring Beans?

Respuesta: No estoy muy seguro (es un proyecto realmente grande), pero por lo que vi creo que está alrededor del 90 al 100%, ya que los archivos xml y de propiedades están aislados en ubicaciones separadas)

Si el problema es realmente el escaneo de componentes y no el proceso de inicialización de bean en sí (y lo dudo mucho), entonces la única solución que puedo imaginar es usar la configuración Spring XML en lugar de análisis de componentes. - (Puede crear el archivo XML automáticamente).

Pero si tiene muchas clases y el 90% - 100% de ellas son Beans, entonces, la reducción de archivos escaneados tendrá una mejora máxima de 10% -0%.

Debe probar otras formas de acelerar su inicialización, puede usar carga lenta o cualquier técnica relacionada con la carga lenta, o (y eso no es una broma) usar hardware más rápido (si no es una aplicación independiente).


Una forma fácil de generar el XML de primavera es escribir una aplicación de primavera simple que utiliza el escaneo de ruta de clase como su aplicación original. Después de inicializar todos los Frijoles, itera a través de los Frijoles en el Contexto de Primavera, comprueba si el frijol pertenece al paquete importante y escribe la configuración XML para este frijol en un archivo.

 9
Author: Ralph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-10 10:23:17

La detección automática de clases anotadas actualmente requiere escanear todas las clases en los paquetes especificados y puede tomar mucho tiempo, un problema conocido del mecanismo de carga de clases actual.

Java 9 va a ayudar aquí con Jigsaw.

Desde el Módulo de la Plataforma Java Requisitos del Sistema por Mark Reinold, http://openjdk.java.net/projects/jigsaw/spec/reqs/ :

Detección eficiente de anotaciones - Debe ser posible identificar todos los archivos de clase en un módulo artefacto en el que una anotación particular está presente sin realmente leer todos los archivos de clase. En tiempo de ejecución debe ser posible identificar todas las clases en un módulo cargado en el que una anotación particular está presente sin enumerar todas las clases en el módulo, siempre y cuando la anotación se conserve durante el tiempo de ejecución. La eficiencia puede ser necesario especificar que sólo ciertas anotaciones deben ser detectables en esta manera. Un enfoque potencial es aumentar la definición con un índice de las anotaciones que están presentes en el módulo, junto con una indicación de los elementos a los que se aplica cada anotación. Para limitar el tamaño del índice, solo se incluirían las anotaciones que a su vez están anotadas con una nueva meta-anotación, por ejemplo @Indexed.

 4
Author: Jeroen Borgers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-25 10:39:13

No hay mucho que pueda hacer sobre el rendimiento allí, supongo que no le preocupa el inicio en el entorno de producción, sino el tiempo de inicio de sus pruebas*. Dos consejos:

  • Revise que su prueba-appcontext solo usa los componentes mínimamente requeridos de su aplicación
  • en lugar de tener una lista de directivas de análisis de componentes, use una, con un valor separado por comas como este: base-package="com.paquete.uno,com.paquete.dos..."
 4
Author: abalogh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-26 21:51:06

Lo único que me viene a la mente, además de reducir los directorios a escanear, es el uso de la inicialización de lazy bean. Que esto podría ayudar si usted tiene una gran cantidad de frijoles

 2
Author: Hons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-10 09:09:16

Sé que es una vieja pregunta, y como verán la situación era diferente en ese momento, pero espero que pueda ayudar a otros a investigar este tema como lo hice yo.

De acuerdo con esta respuesta a una pregunta diferente, la anotación @ComponentScan ahora admite un indicador lazyInit, que debería ayudar a reducir el tiempo de inicio.

Https://stackoverflow.com/a/29832836/4266381

Nota: Su edición hizo que suene como cambiar a XML por sí mismo fue la magia. Sin embargo, mirando más cerca del código, tenías default-lazy-init="true". Me pregunto si esa fue la verdadera razón.

 2
Author: Xiangming Hu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-17 21:31:25

Podría usar la configuración de contenedor basada en Java de Spring en lugar de la exploración de componentes.

En comparación con la configuración basada en XML, la configuración del contenedor basada en Java es segura de tipos.

Pero en primer lugar debe comprobar si las rutas de exploración de sus componentes son lo suficientemente específicas para que no incluyan clases de bibliotecas de terceros.

 1
Author: rwitzel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-19 10:33:50