使用 Grizzly HTTP 服务器线程加载和共享数据存储缓存
Load and share data-store cache with Grizzly HTTP Server threads
我正在 Java SE 应用程序中创建一个 Grizzly http 服务器,指向一个带有 class 的资源包,它处理来自浏览器的 @GET
调用。
默认情况下,Grizzly 最多启动 16 个线程 (0-15),然后再次循环回到线程 0。每次初始化这些线程时(而且,看起来,即使它再次返回到线程 0),它也会调用资源 class 上的构造函数 - 即在每个 GET 请求上调用构造函数,而不仅仅是第一个甚至只是前 16 个(每个线程一个)。
我的构造函数创建了一个 Kafka Streams 数据存储,它不能被多次初始化(好吧,我可以每次分配一个随机标识符,但最终我仍然会遇到冲突),所以我想创建一次并让所有线程都可以访问它。
在资源代码本身有没有一种简单的方法可以做到这一点,还是我最好在别处创建数据存储,然后进行某种跨线程调用来获取信息(在这种情况下,是否有有什么方法可以将该引用注入资源代码,例如将其传递给构造函数?)
或者,我能否让 Grizzly 以某种方式让对象保持活动状态,这样它就不需要继续调用构造函数?如果可能的话,这种方法有什么缺陷?
当前代码:
服务器创建并启动如下:
public static HttpServer startServer()
{
final ResourceConfig rc = new ResourceConfig().packages("com.project.resource.provider");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
return server;
}
JAX-RS 资源:
@Path("/GetFromHere")
public class GetFromHereProvider // in package com.project.resource.provider
{
private final ReadOnlyKeyValueStore<String,DetailObject> kafkaDetailObjectStore;
public GetFromHereProvider() throws Exception
{
// create kafka streams objects and populate kafkaDetailObjectStore. This is being called on every GET request too, for some reason.
}
@GET
@Path("{id}")
@Produces(MediaType.TEXT_PLAIN)
public String getObject(@PathParam("id") String objectID)
{
DetailObject obj= kafkaDetailObjectStore(objectID);
return (obj == null ? "" : obj.toString());
}
}
(以下回答对告知此人非常有帮助:)
这样做的关键是将构造函数逻辑移动到单独的服务 class(术语?),然后在运行时使用依赖注入将该对象的单例实例推送到构造函数中。
新代码如下所示:
- 创建新服务class:
@Singleton
public ServiceProviderClass
{
private final ReadOnlyKeyValueStore<String, DetailObject> kafkaDetailObjectStore;
public ServiceProviderClass()
{
// instantiate kafkaDetailObjectStore...
}
public ReadOnlyKeyValueStore<String, DetailObject> getKafkaDetailObjectStore()
{
return kafkaDetailObjectStore;
}
}
- 创建一个新的绑定程序 class,这将允许注入上述服务 class。我们还告诉它把它当作一个单例,这样它只创建一个对象实例:
public class ServiceProviderClassBinder extends AbstractBinder{
@Override
protected void configure() {
bind(ServiceProviderClass.class)
.to(ServiceProviderClass.class)
.in(Singleton.class);
// alternatively, bind(new ServiceProviderClass()).to(ServiceProviderClass.class) should also work, and then you don't need the .in call.
//If you have Interfaces and Implementations of those Interfaces, the Interface goes in the "to" call, and the concrete implementation in the "bind" call.
//If you don't specify an instance and you don't specify the .in() call, it defaults to instantiating per-call.
}
}
- 更新
GetFromHereProvider
class 以告诉它将服务注入构造函数
@Path("/GetFromHere")
public class GetFromHereProvider // in package com.project.resource.provider
{
private final ServiceProviderClass kafkaDetailObjectStoreServiceProvider;
// CHANGED
@Inject
public GetFromHereProvider(ServiceProviderClass kafkaDetailObjectStoreServiceProvider)
{
this.kafkaDetailObjectStoreServiceProvider = kafkaDetailObjectStoreServiceProvider;
}
@GET
@Path("{id}")
@Produces(MediaType.TEXT_PLAIN)
public String getObject(@PathParam("id") String objectID)
{
DetailObject obj= kafkaDetailObjectStoreServiceProvider.getKafkaDetailObjectStore()(objectID);
return (obj == null ? "" : obj.toString());
}
}
- 最后,在为 Grizzly HTTP 服务器创建 ResourceConfig 时注册绑定器:
public static HttpServer startServer()
{
final ResourceConfig rc = new ResourceConfig().packages("com.project.resource.provider");
// NEW
rc.register(new ServiceProviderClassBinder());
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
return server;
}
我正在 Java SE 应用程序中创建一个 Grizzly http 服务器,指向一个带有 class 的资源包,它处理来自浏览器的 @GET
调用。
默认情况下,Grizzly 最多启动 16 个线程 (0-15),然后再次循环回到线程 0。每次初始化这些线程时(而且,看起来,即使它再次返回到线程 0),它也会调用资源 class 上的构造函数 - 即在每个 GET 请求上调用构造函数,而不仅仅是第一个甚至只是前 16 个(每个线程一个)。
我的构造函数创建了一个 Kafka Streams 数据存储,它不能被多次初始化(好吧,我可以每次分配一个随机标识符,但最终我仍然会遇到冲突),所以我想创建一次并让所有线程都可以访问它。
在资源代码本身有没有一种简单的方法可以做到这一点,还是我最好在别处创建数据存储,然后进行某种跨线程调用来获取信息(在这种情况下,是否有有什么方法可以将该引用注入资源代码,例如将其传递给构造函数?)
或者,我能否让 Grizzly 以某种方式让对象保持活动状态,这样它就不需要继续调用构造函数?如果可能的话,这种方法有什么缺陷?
当前代码:
服务器创建并启动如下:
public static HttpServer startServer()
{
final ResourceConfig rc = new ResourceConfig().packages("com.project.resource.provider");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
return server;
}
JAX-RS 资源:
@Path("/GetFromHere")
public class GetFromHereProvider // in package com.project.resource.provider
{
private final ReadOnlyKeyValueStore<String,DetailObject> kafkaDetailObjectStore;
public GetFromHereProvider() throws Exception
{
// create kafka streams objects and populate kafkaDetailObjectStore. This is being called on every GET request too, for some reason.
}
@GET
@Path("{id}")
@Produces(MediaType.TEXT_PLAIN)
public String getObject(@PathParam("id") String objectID)
{
DetailObject obj= kafkaDetailObjectStore(objectID);
return (obj == null ? "" : obj.toString());
}
}
(以下回答对告知此人非常有帮助:
这样做的关键是将构造函数逻辑移动到单独的服务 class(术语?),然后在运行时使用依赖注入将该对象的单例实例推送到构造函数中。
新代码如下所示:
- 创建新服务class:
@Singleton
public ServiceProviderClass
{
private final ReadOnlyKeyValueStore<String, DetailObject> kafkaDetailObjectStore;
public ServiceProviderClass()
{
// instantiate kafkaDetailObjectStore...
}
public ReadOnlyKeyValueStore<String, DetailObject> getKafkaDetailObjectStore()
{
return kafkaDetailObjectStore;
}
}
- 创建一个新的绑定程序 class,这将允许注入上述服务 class。我们还告诉它把它当作一个单例,这样它只创建一个对象实例:
public class ServiceProviderClassBinder extends AbstractBinder{
@Override
protected void configure() {
bind(ServiceProviderClass.class)
.to(ServiceProviderClass.class)
.in(Singleton.class);
// alternatively, bind(new ServiceProviderClass()).to(ServiceProviderClass.class) should also work, and then you don't need the .in call.
//If you have Interfaces and Implementations of those Interfaces, the Interface goes in the "to" call, and the concrete implementation in the "bind" call.
//If you don't specify an instance and you don't specify the .in() call, it defaults to instantiating per-call.
}
}
- 更新
GetFromHereProvider
class 以告诉它将服务注入构造函数
@Path("/GetFromHere")
public class GetFromHereProvider // in package com.project.resource.provider
{
private final ServiceProviderClass kafkaDetailObjectStoreServiceProvider;
// CHANGED
@Inject
public GetFromHereProvider(ServiceProviderClass kafkaDetailObjectStoreServiceProvider)
{
this.kafkaDetailObjectStoreServiceProvider = kafkaDetailObjectStoreServiceProvider;
}
@GET
@Path("{id}")
@Produces(MediaType.TEXT_PLAIN)
public String getObject(@PathParam("id") String objectID)
{
DetailObject obj= kafkaDetailObjectStoreServiceProvider.getKafkaDetailObjectStore()(objectID);
return (obj == null ? "" : obj.toString());
}
}
- 最后,在为 Grizzly HTTP 服务器创建 ResourceConfig 时注册绑定器:
public static HttpServer startServer()
{
final ResourceConfig rc = new ResourceConfig().packages("com.project.resource.provider");
// NEW
rc.register(new ServiceProviderClassBinder());
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
return server;
}