将单例服务注入 JAX-RS/Jersey 资源的最佳方法是什么?
What is the best way to inject a singleton service into a JAX-RS/Jersey resource?
例如,如果多个资源端点需要访问某些消息总线来处理请求怎么办?当服务 class 本身不是资源但被资源使用时,肯定有一些方法可以注册单例服务 class 并将其注入资源。
我在提供程序或自定义 HK2 绑定中看到的所有示例都引用了资源。
我发现的最接近我要找的东西是这个问题:
Trouble creating a simple singleton class in Jersey 2 using built-in Jersey dependency injection
最好的 JAX-RS/Jersey 方法是什么?
请注意,编程方式最有用,我没有使用 xml 文件来配置服务器。
如果您的平台支持 EJB,您可以使用 @Singleton
EJB(javax.ejb 包,而不是 javax.inject),并使用 @EJB 注释将其注入到您的资源中。单例 EJB 也有开箱即用的并发访问控制。
在普通 Jersey 上,您可以使用 CDI 应用程序上下文。使用 @ApplicationScoped
注释声明服务 class,并使用 @Inject
将其注入您的资源。 CDI只会实例化一个bean。
如果您无法注释服务 class,您可以创建一个方法来提供您的服务实现并使用 @Produces
和 @ApplicationScoped
对其进行注释。
@Produces
@ApplicationScoped
public MyService produceService() {
// instantiate your service client
}
然后在您的资源上使用它:
@Inject
private MyService
答案归功于@areus 。
但是,我提供了我自己的答案,以便我可以共享代码。
服务 Bean
@Singleton
public final class MyServiceBean
{
private static final AtomicInteger INSTANCES = new AtomicInteger();
private final AtomicInteger calls = new AtomicInteger();
public MyServiceBean()
{
INSTANCES.incrementAndGet();
}
public String getMessage()
{
return String.format("MyServiceBean{INSTANCES=%d, CALLED=%d}", INSTANCES.get(), calls.incrementAndGet());
}
}
资源Class
@Path("/messages")
public final class MyResource
{
@Inject
private MyServiceBean bean;
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response handle()
{
return Response.ok(this.bean.getMessage())
.type(MediaType.TEXT_PLAIN_TYPE)
.build();
}
}
HK2活页夹
public final class MyServiceBeanBinder extends AbstractBinder
{
@Override
protected void configure()
{
bind(MyServiceBean.class).to(MyServiceBean.class).in(Singleton.class);
}
}
然后像这样注册活页夹和资源:
final ResourceConfig config = new ResourceConfig();
config.register(MyResource.class);
config.register(new MyServiceBeanBinder());
启动服务器并多次访问资源会产生:
MyServiceBean{INSTANCES=1, CALLED=1}
MyServiceBean{INSTANCES=1, CALLED=2}
MyServiceBean{INSTANCES=1, CALLED=3}
MyServiceBean{INSTANCES=1, CALLED=4}
MyServiceBean{INSTANCES=1, CALLED=5}
例如,如果多个资源端点需要访问某些消息总线来处理请求怎么办?当服务 class 本身不是资源但被资源使用时,肯定有一些方法可以注册单例服务 class 并将其注入资源。
我在提供程序或自定义 HK2 绑定中看到的所有示例都引用了资源。
我发现的最接近我要找的东西是这个问题:
Trouble creating a simple singleton class in Jersey 2 using built-in Jersey dependency injection
最好的 JAX-RS/Jersey 方法是什么?
请注意,编程方式最有用,我没有使用 xml 文件来配置服务器。
如果您的平台支持 EJB,您可以使用 @Singleton
EJB(javax.ejb 包,而不是 javax.inject),并使用 @EJB 注释将其注入到您的资源中。单例 EJB 也有开箱即用的并发访问控制。
在普通 Jersey 上,您可以使用 CDI 应用程序上下文。使用 @ApplicationScoped
注释声明服务 class,并使用 @Inject
将其注入您的资源。 CDI只会实例化一个bean。
如果您无法注释服务 class,您可以创建一个方法来提供您的服务实现并使用 @Produces
和 @ApplicationScoped
对其进行注释。
@Produces
@ApplicationScoped
public MyService produceService() {
// instantiate your service client
}
然后在您的资源上使用它:
@Inject
private MyService
答案归功于@areus
但是,我提供了我自己的答案,以便我可以共享代码。
服务 Bean
@Singleton
public final class MyServiceBean
{
private static final AtomicInteger INSTANCES = new AtomicInteger();
private final AtomicInteger calls = new AtomicInteger();
public MyServiceBean()
{
INSTANCES.incrementAndGet();
}
public String getMessage()
{
return String.format("MyServiceBean{INSTANCES=%d, CALLED=%d}", INSTANCES.get(), calls.incrementAndGet());
}
}
资源Class
@Path("/messages")
public final class MyResource
{
@Inject
private MyServiceBean bean;
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response handle()
{
return Response.ok(this.bean.getMessage())
.type(MediaType.TEXT_PLAIN_TYPE)
.build();
}
}
HK2活页夹
public final class MyServiceBeanBinder extends AbstractBinder
{
@Override
protected void configure()
{
bind(MyServiceBean.class).to(MyServiceBean.class).in(Singleton.class);
}
}
然后像这样注册活页夹和资源:
final ResourceConfig config = new ResourceConfig();
config.register(MyResource.class);
config.register(new MyServiceBeanBinder());
启动服务器并多次访问资源会产生:
MyServiceBean{INSTANCES=1, CALLED=1}
MyServiceBean{INSTANCES=1, CALLED=2}
MyServiceBean{INSTANCES=1, CALLED=3}
MyServiceBean{INSTANCES=1, CALLED=4}
MyServiceBean{INSTANCES=1, CALLED=5}