Взаимодействие между Injection в командах Picocli и micronaut

Определение bean-компонента @Singleton в Micronaut не приводит к @Inject того же экземпляра в команды Picocli.

Micronaut предлагает интеграцию с Пикокли. Что важно сделать, кажется, так это то, что из команды Picocli можно запустить EmbeddedServer Micronaut (может быть, проблема уже здесь, что Micronaut запускается только из Picocli?). Когда я определяю класс как синглтон через @Singleton и @Inject его как в конечной точке Rest в Micronaut, так и в команде Picocli, он замечает, что это два разных экземпляра и состояние не одно и то же. Что мне действительно нужно, так это передать некоторое состояние, предоставленное через интерфейс командной строки, для настройки бэкэнда/Rest-сервиса. На данный момент я только что создал статический экземпляр, чтобы поделиться этим состоянием, но мне интересно, смогу ли я заставить инъекцию зависимостей работать правильно между Picocli и Micronaut.

@Singleton
public class SharedState {
    private int num;

    public void setNum(int num) { this.num = num };
    public int getNum() { return this.num; };
}

@Command(name = "ui", description = "...", mixinStandardHelpOptions = true)
public class UICommand implements Runnable {

    @Inject
    SharedState state;

    public static void main(String[] args) throws Exception {
        PicocliRunner.run(UICommand.class, args);
    }

    public void run() {
        EmbeddedServer server = ApplicationContext.run(EmbeddedServer.class);
        state.setNum(42);
    }
}

@Controller("/rest")
public class RestResource{

    @Inject
    SharedState state;

    @Get
    public String get() {
        return state.getNum();
    }
}

Если я устанавливаю некоторое состояние в экземпляре SharedState в методе run() UICommand, я ожидаю, что смогу прочитать его из RestResource. Итак, я ожидаю получить обратно «42», когда я вызову остальную конечную точку.

Есть ли способ каким-то образом настроить Micronaut/Picocli, чтобы контейнер для внедрения зависимостей Micronaut/Picocli запускался раньше и использовался совместно? Или Micronaut действительно запускается только с вызова EmbeddedServer? В таком случае, какие у меня есть варианты, чтобы по-прежнему иметь некоторую совместимость? Могу ли я каким-то образом явно запросить контейнер DI Micronaut для экземпляра?

Можете ли вы показать метод main, в котором вызывается ваша команда CLI 'ui'? Вы используете один из методов PicocliRunner?

Remko Popma 24.06.2019 10:33

Добавлен основной метод.

38leinad 24.06.2019 14:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
388
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я считаю, что проблема в том, что код в вопросе создает два отдельных экземпляра ApplicationContext.

Вызов PicocliRunner.run(UICommand.class, args) под капотом создает ApplicationContext, в то время как метод UICommand.run вызывает ApplicationContext.run(EmbeddedServer.class), который запускает другой экземпляр ApplicationContext.

Одним из способов решения этой проблемы может быть внедрение ApplicationContext вместо запуска нового:

@Command(name = "ui", description = "...", mixinStandardHelpOptions = true)
public class UICommand implements Runnable {

    @Inject
    SharedState state;

    @Inject
    ApplicationContext appContext;

    public static void main(String[] args) throws Exception {
        PicocliRunner.run(UICommand.class, args);
    }

    public void run() {
        // start the injected, shared, application context (not a new instance)
        if (!appContext.isRunning()) { // future versions of PicocliRunner may start the context
            appContext.start();
        }

        // start the embedded server
        EmbeddedServer server = appContext.getBean(EmbeddedServer.class);
        if (!server.isRunning()) {
            server.start();
        }
        state.setNum(42);
    }
}

Команда Micronaut подтвердила возможность внедрения контекста приложения. Вышеупомянутое решило проблему?

Remko Popma 26.06.2019 03:51

Хорошо, я начинаю понимать, в чем проблема. Но я не могу последовать вашему совету, так как этот код не компилируется. Метод запуска — это статический метод ApplicationContext; не метод экземпляра.

38leinad 26.06.2019 18:52

Ты прав. Я обновил свой ответ. Я не уверен, что все bean-компоненты, которые реализуют LifeCycle (например, EmbeddedServer), автоматически запускаются при запуске контекста приложения, поэтому я явно запускаю EmbeddedServer в приведенном выше примере, но вы можете опустить это.

Remko Popma 27.06.2019 03:20

Спасибо, это сработало. Пришлось запустить сервер, но не контекст.

38leinad 27.06.2019 20:29

Другие вопросы по теме