How to use CXF, JAX-RS and HTTP Caching

前端 未结 3 1384
梦如初夏
梦如初夏 2021-01-30 18:20

The CXF documentation mentions caching as Advanced HTTP:

CXF JAXRS provides support for a number of advanced HTTP features by handling If-Match, If-Modifi

相关标签:
3条回答
  • 2021-01-30 18:58

    Actually, the answer isn't specific to CXF - it's pure JAX-RS:

    // IPersonService.java
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.Request;
    import javax.ws.rs.core.Response;
    
    @GET
    @Path("/person/{id}")
    Response getPerson(@PathParam("id") String id, @Context Request request);
    
    
    // PersonServiceImpl.java
    import javax.ws.rs.core.CacheControl;
    import javax.ws.rs.core.EntityTag;
    import javax.ws.rs.core.Request;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.core.Response.ResponseBuilder;
    
    public Response getPerson(String name, Request request) {
      Person person = _dao.getPerson(name);
    
      if (person == null) {
        return Response.noContent().build();
      }
    
      EntityTag eTag = new EntityTag(person.getUUID() + "-" + person.getVersion());
    
      CacheControl cc = new CacheControl();
      cc.setMaxAge(600);
    
      ResponseBuilder builder = request.evaluatePreconditions(person.getUpdated(), eTag);
    
      if (builder == null) {
        builder = Response.ok(person);
      }
    
      return builder.cacheControl(cc).lastModified(person.getUpdated()).build();
    }
    
    0 讨论(0)
  • 2021-01-30 19:00

    With the forthcoming JAX-RS 2.0 it will be possible to apply Cache-Control declaratively, as explained in http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/

    You can already test this at least with Jersey. Not sure about CXF and RESTEasy though.

    0 讨论(0)
  • 2021-01-30 19:11

    CXF didn't implements dynamic filtering as explained here : http://www.jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0

    And if you use to return directly your own objects and not CXF Response, it's hard to add a cache control header.

    I find an elegant way by using a custom annotation and creating a CXF Interceptor that read this annotation and add the header.

    So first, create a CacheControl annotation

    @Target(ElementType.METHOD )
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CacheControl {
        String value() default "no-cache";
    }
    

    Then, add this annotation to your CXF operation method (interface or implementation it works on both if you use an interface)

    @CacheControl("max-age=600")
    public Person getPerson(String name) {
        return personService.getPerson(name);
    }
    

    Then create a CacheControl interceptor that will handle the annotation and add the header to your response.

    public class CacheInterceptor extends AbstractOutDatabindingInterceptor{
        public CacheInterceptor() {
            super(Phase.MARSHAL);
        }
    
        @Override
        public void handleMessage(Message outMessage) throws Fault {
            //search for a CacheControl annotation on the operation
            OperationResourceInfo resourceInfo = outMessage.getExchange().get(OperationResourceInfo.class);
            CacheControl cacheControl = null;
            for (Annotation annot : resourceInfo.getOutAnnotations()) {
                if(annot instanceof CacheControl) {
                    cacheControl = (CacheControl) annot;
                    break;
                }
            }
    
            //fast path for no cache control
            if(cacheControl == null) {
                return;
            }
    
            //search for existing headers or create new ones
            Map<String, List<String>> headers = (Map<String, List<String>>) outMessage.get(Message.PROTOCOL_HEADERS);
            if (headers == null) {
                headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
                outMessage.put(Message.PROTOCOL_HEADERS, headers);
            }
    
            //add Cache-Control header
            headers.put("Cache-Control", Collections.singletonList(cacheControl.value()));
        }
    }
    

    Finally configure CXF to use your interceptor, you can find all the needed information here : http://cxf.apache.org/docs/interceptors.html

    Hope it will help.

    Loïc

    0 讨论(0)
提交回复
热议问题