Проблемы с производительностью при запуске Spring - PullRequest
36 голосов
/ 10 мая 2011

Я пытаюсь интегрировать Spring в довольно большое приложение с тысячами классов, и у меня возникают огромные задержки при запуске моего контейнера из-за сканирования компонентов.

Я уже сузил число каталогов, указанных в «базовом пакете», до минимума, чтобы сократить время, затрачиваемое на сканирование несоответствующих каталогов, но сканирование инициализации по пути классов по-прежнему занимает около 1-2 мин.

Итак, есть ли способ оптимизировать процесс сканирования? Я думал о том, чтобы сохранить путь к классам-кандидатам в файле и сделать контейнер, а затем получить их из файла вместо сканирования пути к классам при каждом запуске, но я не знаю, с чего начать, или если это вообще возможно .

Любой совет очень ценится. Заранее спасибо.

Редактировать : загрузка определений bean-компонентов из автоматически сгенерированного XML-файла сократила время начальной загрузки Spring до 9 ~ 10 секунд, что подтверждает, что API-интерфейс отражения, используемый Spring для сканирования пути классов компонентов, является основным источником задержек запуска.
Что касается генерации XML-файла, здесь приведен код, поскольку он может быть полезен для тех, кто сталкивается с такими же проблемами.

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>");
    }

}

Ответы [ 6 ]

9 голосов
/ 10 мая 2011

Вопрос: Сколько (в%) классов в каталогах составляют Spring Beans?

Ответ: Я не совсем уверен (это действительно большой проект), но из того, что я увидел, я считаю, что он составляет от 90 до 100%, так как XML-файлы и файлы свойств изолированы в разных местах)

Если проблема действительно в сканировании компонентов, а не в самом процессе инициализации компонента (и я в этом сильно сомневаюсь), то единственное решение, которое я могу себе представить, - это использовать конфигурацию Spring XML вместо сканирования компонентов.- (Можно создать файл XML автоматически).

Но если у вас много классов и 90% - 100% из них являются бобами, то уменьшение отсканированных файлов будет иметь максимальное улучшение на 10%.-0%.

Вам следует попробовать другие способы ускорить инициализацию, возможно, с использованием отложенной загрузки или любых других методов, связанных с отложенной загрузкой, или (и это не шутка) использование более быстрого оборудования (если оно не являетсяавтономное приложение).


Простой способ создания Spring XML - это написать простое приложение Spring, которое использует сканирование пути класса, как ваше оригинальное приложение.После инициализации всех Бинов он проходит по Бинам в контексте Spring, проверяет, принадлежит ли бин к важному пакету, и записывает XML-конфигурацию для этого бина в файл.

4 голосов
/ 25 октября 2015

Автоматическое обнаружение аннотированных классов в настоящее время требует сканирования всех классов в указанных пакетах и ​​может занять длительное время, что является известной проблемой текущего механизма загрузки классов.

Java 9 поможет вам с Jigsaw.

Из модуля платформы Java Системные требования Марка Рейнольда, http://openjdk.java.net/projects/jigsaw/spec/reqs/:

Эффективное обнаружение аннотаций - Должна быть возможность идентифицировать все файлы классов в артефакте модуля, в котором присутствует конкретная аннотация, без фактического чтения всех файлов классов. Во время выполнения должна быть возможность идентифицировать все классы в загруженном модуле, в котором присутствует конкретная аннотация, без перечисления всех классов в модуле, при условии, что аннотация была сохранена для времени выполнения. Для эффективности может потребоваться указать, что только определенные аннотации должны обнаруживаться таким образом. Один из возможных подходов состоит в том, чтобы дополнить определение модуля индексом аннотаций, присутствующих в модуле, вместе с указанием элементов, к которым применяется каждая аннотация. Чтобы ограничить размер индекса, будут включены только аннотации, которые сами помечены новой метааннотацией, скажем, @Indexed.

4 голосов
/ 10 мая 2011

Вы мало что можете сделать с производительностью, я думаю, вы беспокоитесь не о запуске в производственной среде, а о времени запуска ваших тестов *.Два совета:

  • Обратите внимание, что ваш test-appcontext использует только минимально необходимые компоненты вашего приложения
  • вместо списка директив компонентного сканирования, используйте один с запятойзначение, разделенное следующим образом: base-package = "com.package.one, com.package.two ..."
2 голосов
/ 18 сентября 2017

Я знаю, что это старый вопрос, и, как вы увидите, в то время ситуация была иной, но, надеюсь, это может помочь другим, исследующим эту проблему, как и я.

Согласно этому ответу на другой вопрос, аннотация @ComponentScan теперь поддерживает флаг lazyInit, который должен помочь в сокращении времени запуска.

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

Примечание. Ваше редактирование показалось, что переключение на XML само по себе было волшебством. И все же, присмотревшись к коду, вы получили default-lazy-init="true". Интересно, была ли это истинная причина?

2 голосов
/ 19 марта 2014

Вместо сканирования компонентов можно использовать Spring-конфигурацию контейнера на основе Java.

По сравнению с конфигурацией на основе XML конфигурация контейнера на основе Java является типобезопасной.

Но прежде всего вы должны проверить, достаточно ли специфичны пути сканирования ваших компонентов, чтобы они не включали в себя классы сторонних библиотек.

2 голосов
/ 10 мая 2011

Единственное, что приходит мне на ум, помимо сокращения количества сканируемых каталогов, это использование lazy bean initialization .Может ли это помочь, если у вас много бобов

...