在Jersey(HK2)中按名称动态查找服务

时间:2019-06-25 06:29:27

标签: java dependency-injection jersey hk2

在我的应用程序中,我需要根据一些用户输入获取不同的实现。

由于我想充分利用HK2的优势,所以我想用Jersey / HK2提供的方法解决这个问题。

到目前为止,我所做的只是通过接口绑定服务,这些接口使用ApplicationConfigApplicationBinder绑定到启动时的实现:

@javax.ws.rs.ApplicationPath("api")
public class ApplicationConfig extends ResourceConfig
{
    public ApplicationConfig()
    {
        super();
        packages(true, "my.package");
        register(new ApplicationBinder());
        register(....);
        ....
    }
}

public class ApplicationBinder extends AbstractBinder
{
    @Override
    protected void configure()
    {
        bind(ServletTemplateLoader.class).to(TemplateLoader.class);
        bindAsContract(JobsImpl.class);
        bindAsContract(JobInputAppender.class);
        bindAsContract(ParamNameMapper.class);
        bind(RedisJobRepository.class).to(JobRepositoryInterface.class);
        ....
    }

现在,我需要根据用户输入动态获取一个实现。有25种不同的实现方式都使用同一接口。

这意味着,我不能再简单地使用bind.to方法了。相反,我认为我需要分别向bindAsContract注册它们。

但是,我该如何为任何给定的输入(来自用户)编写一个方法/类为我提供正确的实现?

本质上,我需要一种如下所示的方法:

public interface MyInterface {}
public class Type1Impl implements MyInterface {} // registered with `bindAsContract`

public MyInterface getImplementation(final String type_)
{
    switch (type_) {
        case "type1":
            return // what to do here to get "my.package.Type1Impl" instance?
        case "type":
            ....
    }
}

我需要实例来自HK2,因为Impl也使用注入服务,因此我不能简单地动态创建新实例。

2 个答案:

答案 0 :(得分:2)

我认为使用IterableProvider会有更好的答案。基本上,您可以在一项服务中做到这一点:

AdminClient
  .create(props)
  .listTopics()
  .names()
  .toCompletableFuture
  .asScala

希望这会有所帮助!

答案 1 :(得分:0)

因此,经过数小时的搜索却没有答案,我感到沮丧和盘旋,想着“好吧,尽力去做你能想到的最明显的事情”。

在DI的情况下,只是告诉容器给我我想要的东西。

事实证明,这种方法行之有效,而且几乎是无足轻重的……

public interface MyInterface {}
public class Type1Impl implements MyInterface {}
public class Type2Impl implements MyInterface {}

@javax.ws.rs.ApplicationPath("api")
public class ApplicationConfig extends ResourceConfig
{
    public ApplicationConfig()
    {
        super();
        packages(true, "my.package");
        register(new ApplicationBinder());
    }
}

public class ApplicationBinder extends AbstractBinder
{
    @Override
    protected void configure()
    {
        bindAsContract(ImplementationGetter.class);
        bind(Type1Impl.class).to(MyInterface.class).named("type1");
        bind(Type2Impl.class).to(MyInterface.class).named("type2");
    }
}

public class ImplementationGetter {
    @Inject
    private ServiceLocator _locator;

    public MyInterface getImplementation(final String type_)
    {
        switch (type_) {
            case "type1":
                return _locator.getService(MyInterface.class, "type1");
            case "type2":
                return _locator.getService(MyInterface.class, "type2");
        }
    }
}