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:
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
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:
return type Reponse
is generic
missing grammar of return type in WADL
dependency injection with @Context
is complicated, see https://stackoverflow.com/questions/33240443
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:
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.