1

在 Micronaut 中定义 @Singleton bean 不会 @Inject 相同的实例到 Picocli 命令中。

Micronaut 提供与Picocli的集成。看起来最重要的是,从 Picocli 命令中,可以启动 Micronaut 的 EmbeddedServer(也许问题已经在这里,Micronaut 只是真正从 Picocli 内部启动?)。当我通过@Singleton 将一个类定义为单例,并在Micronaut 的Rest-endpoint 和Picocli 命令中对其进行@Inject 时,它注意到这是两个不同的实例,并且状态不一样。我主要想要的是传输通过命令行界面提供的一些状态来配置后端/Rest-service。现在我刚刚创建了静态实例来共享这个状态,但我想知道我是否可以让依赖注入在 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();
    }
}

如果我在 UICommand 的 run() 方法中的 SharedState 实例中设置了一些状态,我希望能够从 RestResource 中读取它。因此,当我调用其余端点时,我希望返回“42”。

有没有办法以某种方式设置 Micronaut/Picocli,以便尽早启动并共享 Micronaut/Picocli 的依赖注入容器?还是 Micronaut 真的只是从 EmbeddedServer 调用开始的?在那种情况下,我必须有哪些选择才能仍然具有一些互操作性?我可以以某种方式明确地向 Micronaut 的 DI 容器询问该实例吗?

4

1 回答 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);
    }
}
于 2019-06-25T10:16:33.563 回答