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
How to cache response with Jersey?
提问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 resource
with your Resource instance.
替换resource
为您的 Resource 实例。
回答by dur
Summary of solutions:
解决方案总结:
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
Request
is exposedreturn type
Reponse
is genericmissing grammar of return type in WADL
client proxywith unnecessary parameter
Request
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:
return type
Reponse
is genericmissing grammar of return type in WADL
dependency injection with
@Context
is complicated, see https://stackoverflow.com/questions/33240443
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:
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
请求作为方法参数
界面:
@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
请求作为实例变量
界面:
@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(); } }
缺点:
返回类型
Reponse
是通用的WADL 中缺少返回类型的语法
依赖注入
@Context
很复杂,见https://stackoverflow.com/questions/33240443
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; } }
缺点:
自定义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.
希望能帮助到你。