Как уменьшить медленный запуск приложений Picocli из-за отражения

Picocli должен проанализировать дерево команд. При этом ему необходимо загружать классы объектов домена для каждой команды, что замедляет запуск jvm.

Какие варианты есть, чтобы избежать этой задержки запуска? Одно решение, которое я придумал, описано в https://github.com/remkop/picocli/issues/482:

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

abstract class BaseCommand implements Runnable {

    interface CommandExecutor {
        Object doExecute() throws Exception;
    }

    // find the CommandExecutor declared at the BaseCommand subclass.
    protected Object executeReflectively() throws Exception {
        Class<?> innerClass = getExecutorInnerClass();
        Constructor<?> ctor = innerClass.getDeclaredConstructor(getClass());
        CommandExecutor exec = (CommandExecutor) ctor.newInstance(this);
        return exec.doExecute();
    }

    private Class<?> getExecutorInnerClass() throws ClassNotFoundException {
        return getClass().getClassLoader().loadClass(getClass().getName() + "$Executor");
    }

    public void run() {
        try {
             executeReflectively();
       } catch(...){
          /// usual stuff
       }
    }
}

Конкретный класс рекомендаций:

@Command(...) 
final class CopyProfile extends BaseCommand {
    @Option String source;
    @Option String dest;

    // class must NOT be static and must be called "Executor"
    public class Executor implements CommandExecutor {
        @Override
        public Object doExecute() throws Exception {
           // you can basically wrap your original run() with this boilerplate
           // all the CopyProfile's field are in scope!
          FileUtils.copy(source, dest);
        }
    }
}

Похоже на https://github.com/remkop/picocli/issues/500 может обеспечить окончательное решение этой проблемы. Какие еще есть варианты до этого?


person julius    schedule 29.09.2018    source источник
comment
Можете ли вы из интереса предоставить некоторые цифры времени запуска для исходного кода и после вашего изменения?   -  person Remko Popma    schedule 30.09.2018


Ответы (1)


ОБНОВЛЕНИЕ, февраль 2020 г.:

Обновление до последней версии picocli должно решить эту проблему. Из примечаний к выпуску 4.2.0 picocli:

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


Альтернативой, не требующей каких-либо изменений кода, является использование GraalVM для компиляции вашего приложения на основе picocli в собственный образ.

В этой статье показано, как это сделать, и полученное время запуска составляет 3 миллисекунды.

Пример приложения на основе picocli, работающего на GraalVM

person Remko Popma    schedule 04.10.2018
comment
Это хорошо, но имейте в виду, что если вы импортируете что-либо, использующее java.lang.SecurityManager, это не сработает. Я понял это на собственном горьком опыте, когда пытался сделать это со своим приложением, которое интенсивно взаимодействовало с AWS SDK. - person SalmonKiller; 07.12.2018
comment
@SalmonKiller Это хорошая информация, я не знал об этом! Не могли бы вы создать тикет в системе отслеживания проблем picocli с более подробной информацией, чтобы мы могли задокументировать это для других пользователей? - person Remko Popma; 07.12.2018