如何使用Jersey缓存响应?

时间:2013-02-26 11:23:37

标签: java rest jersey

我正在尝试使用Jersey开发restful API。我有一个特定的get操作的GET API,我的GET从同一个客户端同时进行。 是否可以缓存响应?任何指针都表示赞赏。

由于

4 个答案:

答案 0 :(得分:10)

您可以使用CacheControl,eTag - 按照下面的示例代码

// In your jersey method
    final EntityTag eTag = new EntityTag(resource.getId() + "_" +
     resource.getLastModified().getTime());
    final CacheControl cacheControl = new CacheControl();
    cacheControl.setMaxAge(-1);

    ResponseBuilder builder = request.evaluatePreconditions(
         resource.getLastModified(), eTag);

    // the resoruce's information was modified, return it
    if (builder == null) {
         builder = Response.ok(resource);
    }

    // the resource's information was not modified, return a 304

    return builder.cacheControl(cacheControl).lastModified(
         resource.getLastModified()).tag(eTag).build();

resource替换为您的资源实例。

答案 1 :(得分:6)

解决方案摘要:

  1. Request作为方法参数

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getMyEntity(@Context final Request request);
    }
    

    实现:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Override
        public Response getMyEntity(final Request request) {
    
            final MyEntity myEntity = ... // load entity
            final String eTagValue = ... // calclutate value of ETag
    
            final EntityTag eTag = new EntityTag(eTagValue);
    
            ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
            if (responseBuilder == null) {
                return Response.ok(user).tag(eTag).build();
            }
    
            return responseBuilder.build();
        }
    }
    

    缺点:

    • 实施细节Request已曝光

    • 返回类型Reponse是通用的

    • 在WADL中缺少返回类型的语法

    • client proxy包含不必要的参数Request

  2. Request作为实例变量

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getMyEntity();
    }
    

    实现:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Context
        private Request request
    
        @Override
        public Response getMyEntity() {
    
            final MyEntity myEntity = ... // load entity
            final String eTagValue = ... // calclutate value of ETag
    
            final EntityTag eTag = new EntityTag(eTagValue);
    
            ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
            if (responseBuilder == null) {
                return Response.ok(user).tag(eTag).build();
            }
    
            return responseBuilder.build();
        }
    }
    

    缺点:

  3. ShallowEtagHeaderFilter作为网络过滤器

    的web.xml:

    <filter>
        <filter-name>etagFilter</filter-name>
        <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>etagFilter</filter-name>
        <url-pattern>/api/*</url-pattern>
    </filter-mapping>
    

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public MyEntity getMyEntity();
    }
    

    实现:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Override
        public MyEntity getMyEntity() {
    
            final MyEntity myEntity = ... // load entity
            return myEntity;
        }
    }
    

    缺点:

    • 服务器性能不佳,请参阅JavaDoc

    • 仅适用于未提交的响应

    • 不支持weak ETag

  4. 自定义WriterInterceptorJAX-RS Interceptor

    拦截器:

    public class CustomInterceptor implements WriterInterceptor {
    
        @Context
        private Request request;
    
        @Override
        public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
    
            OutputStream old = context.getOutputStream();
    
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    
            try {
    
                context.setOutputStream(buffer);
                context.proceed();
    
                byte[] entity = buffer.toByteArray();
    
                String etag = ... // calclutate value of ETag
                context.getHeaders().putSingle(HttpHeaders.ETAG, etag);
    
                ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
                if (responseBuilder == null) {
                     throw new WebApplicationException(responseBuilder.status(Response.Status.NOT_MODIFIED).header(HttpHeaders.ETAG, etag).build());
                }
    
                old.write(entity);
    
            } finally {
                context.setOutputStream(old);
            }
        }
    }
    

    另见:ServerCacheInterceptor(Resteasy)

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public MyEntity getMyEntity();
    }
    

    实现:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Override
        public MyEntity getMyEntity() {
    
            final MyEntity myEntity = ... // load entity
            return myEntity;
        }
    }
    

    缺点:

    • 没有适用于Jersey的预定义拦截器

    • 糟糕的服务器性能

    • 不支持weak ETag

    • 使用WebApplicationException

    • 进行丑陋的解决方法

答案 2 :(得分:3)

您可以将任何适用于标准java的缓存机制与Jersey一起使用,例如Ehcache

您只需要注意验证后端中的数据是否未发生变化。

以下是Ehcache的简单示例:

@GET
@Path("{id}")
public List<Data> getData(@PathParam("id") Long id) {
    Element element = CacheManager.getInstance().getCache("test").get(id);
    if(element == null) {
        Data value = fetchElementFromBackend(id);
        CacheManager.getInstance().getCache("test").put(new Element(id, value));
        return value;
    }

    return element.getObjectValue();
}

答案 3 :(得分:0)

最近,我一直在解决类似(如果不一样)的问题。作为附带结果,出现了以下库:https://bitbucket.org/Andrey-Lebedenko/caching-filter

它的使用方式如下:

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/cached")
@ResponseCachedByFilter(10000)
public Object getCached() {
    return dao.get();
} 

希望有帮助。