java 如何使用 Jersey 缓存响应?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15087831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 18:26:43  来源:igfitidea点击:

How to cache response with Jersey?

javarestjersey

提问by chiru

I am trying to develop restful API using Jersey.I have GET API's for a particular get operation my GET is taking same time from the same client. Is it possible to cache response? Any pointers is appreciated.

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

Thanks

谢谢

回答by TheWhiteRabbit

You can use CacheControl, eTag - follow below example code

您可以使用 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();

Replace resourcewith your Resource instance.

替换resource为您的 Resource 实例。

回答by dur

Summary of solutions:

解决方案总结:

  1. Requestas method parameter

    Interface:

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

    Implementation:

    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();
        }
    }
    

    Disadvantages:

    • implementation detail Requestis exposed

    • return type Reponseis generic

    • missing grammar of return type in WADL

    • client proxywith unnecessary parameter Request

  2. Requestas instance variable

    Interface:

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

    Implementation:

    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();
        }
    }
    

    Disadvantages:

  3. ShallowEtagHeaderFilteras web filter

    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>
    

    Interface:

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

    Implementation:

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

    Disadvantages:

    • bad server performance, see JavaDoc

    • works only on uncommitted response

    • no support of weak ETag

  4. Custom WriterInterceptoras JAX-RS Interceptor

    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);
            }
        }
    }
    

    See also: ServerCacheInterceptor(Resteasy)

    Interface:

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

    Implementation:

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

    Disadvantages:

    • no predefined interceptor for Jersey available

    • bad server performance

    • no support of weak ETag

    • ugly workaround with WebApplicationException

  1. 请求作为方法参数

    界面:

    @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 中缺少返回类型的语法

    • 带有不必要参数的客户端代理Request

  2. 请求作为实例变量

    界面:

    @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作为网络过滤器

    网页.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

    • 仅适用于未提交的响应

    • 不支持弱 ETag

  4. 自定义WriterInterceptor作为JAX-RS 拦截器

    拦截器:

    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;
        }
    }
    

    缺点:

    • 泽西岛没有可用的预定义拦截器

    • 服务器性能不佳

    • 不支持弱 ETag

    • 丑陋的解决方法 WebApplicationException

回答by flash

You could use any caching mechanism applicable for standard java together with Jersey, like Ehcache.

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

You only have to pay attention to verify that your data in the backend hasn't changed.

你只需要注意验证你在后端的数据没有改变。

Here is simple example with 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();
}

回答by Andrey Lebedenko

Recently I've been solving the similar (if not the same) problem. As a side result of it the following library emerged: https://bitbucket.org/Andrey-Lebedenko/caching-filter

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

The way it can be used is like below:

它的使用方式如下:

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

Hope it helps.

希望能帮助到你。