在 Jersey (HK2) 中按名称动态查找服务
Dynamically find service by name in Jersey (HK2)
在我的应用程序中,我需要根据某些用户输入获取不同的实现。
因为我想充分利用 HK2 我想用 Jersey/HK2 提供的方法解决这个问题。
到目前为止,我所做的只是通过接口注入服务,这些接口在启动时使用 ApplicationConfig
和 ApplicationBinder
:
绑定到实现
@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
.
单独注册它们
但是,我该如何编写一个 method/class 来为任何给定的输入(来自用户)提供正确的实现?
本质上,我需要一个如下所示的方法:
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 也使用注入服务,所以我不能简单地即时创建一个新实例。
所以在搜索了几个小时没有得到答案后,我感到很沮丧并转回原处,想 "ok just try to do the most obvious thing you can think of"。
在 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");
}
}
}
我认为使用 IterableProvider 会有更好的答案。基本上你可以在你的一项服务中做到这一点:
public class ImplementationGetter {
@Inject
private IterableProvider<MyInterface> interfaceProvider;
public MyInterface getImplementation(final String type_) {
return interfaceProvider.named(type_).get();
}
}
希望对您有所帮助!
在我的应用程序中,我需要根据某些用户输入获取不同的实现。
因为我想充分利用 HK2 我想用 Jersey/HK2 提供的方法解决这个问题。
到目前为止,我所做的只是通过接口注入服务,这些接口在启动时使用 ApplicationConfig
和 ApplicationBinder
:
@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
.
但是,我该如何编写一个 method/class 来为任何给定的输入(来自用户)提供正确的实现?
本质上,我需要一个如下所示的方法:
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 也使用注入服务,所以我不能简单地即时创建一个新实例。
所以在搜索了几个小时没有得到答案后,我感到很沮丧并转回原处,想 "ok just try to do the most obvious thing you can think of"。
在 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");
}
}
}
我认为使用 IterableProvider 会有更好的答案。基本上你可以在你的一项服务中做到这一点:
public class ImplementationGetter {
@Inject
private IterableProvider<MyInterface> interfaceProvider;
public MyInterface getImplementation(final String type_) {
return interfaceProvider.named(type_).get();
}
}
希望对您有所帮助!