简体   繁体   中英

How to cache response with Jersey?

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.

Thanks

You can use CacheControl, eTag - follow below example code

// 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.

Summary of solutions:

  1. Request as 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 exposed

    • return type Reponse is generic

    • missing grammar of return type in WADL

    • client proxy with unnecessary parameter Request

  2. Request as 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. ShallowEtagHeaderFilter as 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 WriterInterceptor as 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

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

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

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

Recently I've been solving a similar (if not the same) problem. As a side result of it the following library emerged: https://github.com/AndreyLebedenko/dropwizard-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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM