【问题标题】:Dynamically find service by name in Jersey (HK2)在 Jersey (HK2) 中按名称动态查找服务
【发布时间】:2019-06-25 06:29:27
【问题描述】:

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

因为我想充分利用 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 也使用注入服务,所以我不能简单地即时创建一个新实例。

【问题讨论】:

    标签: java dependency-injection jersey hk2


    【解决方案1】:

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

    public class ImplementationGetter {
      @Inject
      private IterableProvider<MyInterface> interfaceProvider;
    
      public MyInterface getImplementation(final String type_) {
        return interfaceProvider.named(type_).get();
      }
    }
    

    希望这会有所帮助!

    【讨论】:

    • 好主意,我想我会选择这个。看起来干净一些。
    【解决方案2】:

    所以在几个小时没有答案的搜索之后,我感到沮丧并转过身来,想“好吧,试着做你能想到的最明显的事情”。

    在 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");
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 2013-07-12
      • 2014-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多