在 JAX-RS 中使用 @Context、@Provider 和 ContextResolverRS、JAX、Context、ContextResolver

2023-09-06 10:52:47 作者:初夏、夜微凉

我刚刚熟悉使用 JAX-RS 在 Java 中实现 REST Web 服务,但遇到了以下问题.我的资源类之一需要访问存储后端,该后端被抽象为 StorageEngine 接口.我想将当前的 StorageEngine 实例注入到服务于 REST 请求的资源类中,我认为这样做的一个好方法是使用 @Context 注释和适当的 ContextResolver 类.这是我目前所拥有的:

I'm just getting acquainted with implementing REST web services in Java using JAX-RS and I ran into the following problem. One of my resource classes requires access to a storage backend, which is abstracted away behind a StorageEngine interface. I would like to inject the current StorageEngine instance into the resource class serving the REST requests and I thought a nice way of doing this would be by using the @Context annotation and an appropriate ContextResolver class. This is what I have so far:

MyResource.java 中:

class MyResource {
    @Context StorageEngine storage;
    [...]
}

StorageEngineProvider.java中:

@Provider
class StorageEngineProvider implements ContextResolver<StorageEngine> {
    private StorageEngine storage = new InMemoryStorageEngine();

    public StorageEngine getContext(Class<?> type) {
        if (type.equals(StorageEngine.class))
            return storage;
        return null;
    }
}

我正在使用 com.sun.jersey.api.core.PackagesResourceConfig 自动发现提供程序和资源类,并根据日志获取 StorageEngineProvider 类很好(时间戳和不必要的东西故意遗漏):

I'm using com.sun.jersey.api.core.PackagesResourceConfig to discover the providers and the resource classes automatically, and according to the logs, it picks up the StorageEngineProvider class nicely (timestamps and unnecessary stuff left out intentionally):

INFO: Root resource classes found:
    class MyResource
INFO: Provider classes found:
    class StorageEngineProvider

但是,我的资源类中 storage 的值始终是 null - 既不是 StorageEngineProvider 的构造函数,也不是它的 getContext 方法由 Jersey 调用,永远.我在这里做错了什么?

However, the value of storage in my resource class is always null - neither the constructor of StorageEngineProvider nor its getContext method is called by Jersey, ever. What am I doing wrong here?

推荐答案

我不认为有特定的 JAX-RS 方式来做你想做的事.最接近的做法是:

I don't think there's a JAX-RS specific way to do what you want. The closest would be to do:

@Path("/something/")
class MyResource {
    @Context
    javax.ws.rs.ext.Providers providers;

    @GET
    public Response get() {
        ContextResolver<StorageEngine> resolver = providers.getContextResolver(StorageEngine.class, MediaType.WILDCARD_TYPE);
        StorageEngine engine = resolver.get(StorageEngine.class);
        ...
    }
}

但是,我认为 @javax.ws.rs.core.Context 注释和 javax.ws.rs.ext.ContextResolver 确实适用于与 JAX-RS 相关的类型并支持 JAX-RS 提供程序.

However, I think the @javax.ws.rs.core.Context annotation and javax.ws.rs.ext.ContextResolver is really for types related to JAX-RS and supporting JAX-RS providers.

您可能希望在此处查找 Java 上下文和依赖注入 (JSR-299) 实现(应该在 Java EE 6 中可用)或其他依赖注入框架(例如 Google Guice)来帮助您.

You may want to look for Java Context and Dependency Injection (JSR-299) implementations (which should be available in Java EE 6) or other dependency injection frameworks such as Google Guice to help you here.