Interoperability between Injections in Picocli commands and micronaut

元气小坏坏 提交于 2020-01-16 04:18:11

问题


Defining an @Singleton bean in Micronaut does not @Inject the same instance into Picocli commands.

Micronaut offers an integration with Picocli. What is essential done, it seems, is that from the Picocli command, one can start an EmbeddedServer of Micronaut (maybe the problem is already here that Micronaut is started only really started from within Picocli?). When I define a class as singleton via @Singleton, and @Inject it both in a Rest-endpoint of Micronaut and the Picocli command, it notice that these are two different instances and the state is not the same. What I essential want is to transport some state provided via the commandline interface to configure the backend/Rest-service. For now I have just created static instance to share this state but i am wondering if I can get the dependency-injection to work properly between Picocli and 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();
    }
}

If I set some state in the SharedState instance in the UICommand's run()-method, I expect to be able to read it from the RestResource. So, i would expect to get back "42" when i call the rest endpoint.

Is there some way to set up Micronaut/Picocli in some way so the dependency-injection container of Micronaut/Picocli is started early and shared? Or is Micronaut really only started with the EmbeddedServer call? In that case, what options to I have to still have some interoperability? Can i explicitly ask Micronaut's DI container for the instance in some way?


回答1:


I believe that the problem is that the code in the question creates two separate ApplicationContext instances.

The call to PicocliRunner.run(UICommand.class, args) under the hood creates an ApplicationContext, while the UICommand.run method calls ApplicationContext.run(EmbeddedServer.class), which starts another ApplicationContext instance.

One way to solve this may be to inject the ApplicationContext instead of starting a new one:

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


来源:https://stackoverflow.com/questions/56730965/interoperability-between-injections-in-picocli-commands-and-micronaut

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!