2012-06-07 15 views
20

RESTful web hizmeti yazarken, istemcimde (şu anda .NET kalın istemcisi) herhangi bir önbelleğe alma özelliğini etkinleştirirseniz sorunlarla karşılaşıyorum. Varsayılan olarak Jersey herhangi bir önbellek denetimi üstbilgisi göndermez, bu nedenle istemci çoğu sayfayı otomatik olarak önbelleğe alır (geçerli davranış gibi görünüyor).Jersey: Önbellek için varsayılan Önbellek Denetimi

Varsayılan olarak "no-cache" önbellek denetimi göndererek Jersey'e sahip olmak isterim ve daha sonra özellikle önbellek denetimini geçersiz kılar.

Bunu Jersey ile yapmanın bir yolu var mı?

RESTeasy'nin, tüm sınıfın ayarlarını belirtmek için @NoCache ek açıklamasını kullanma yeteneğine sahip olduğunu buldum, ancak Jersey ile benzer bir şey bulamadım.

cevap

23

Bu, bir ResourceFilterFactory kullanarak Jersey ile kolaydır - önbellek denetimi ayarlarını yapmak için yöntemlere eklediğiniz herhangi bir özel açıklama oluşturabilirsiniz. ResourceFilterFactories, uygulama başlatıldığında her keşfedilen kaynak yöntemi için çağrılır - ResourceFilterFactory içinde, yöntemin @CacheControlHeader ek açıklamasının olup olmadığını kontrol edebilirsiniz (veya ne isterseniz onu çağırmak) - eğer değilse, sadece "no-cache" ekleyen yanıt filtresini döndürün "cevaba direktifi, aksi takdirde ek açıklamadan ayarları kullanmalıdır. İşte nasıl yapılacağı bir örnek olduğunu:

public class CacheFilterFactory implements ResourceFilterFactory { 
    private static final List<ResourceFilter> NO_CACHE_FILTER = Collections.<ResourceFilter>singletonList(new CacheResponseFilter("no-cache")); 

    @Override 
    public List<ResourceFilter> create(AbstractMethod am) { 
     CacheControlHeader cch = am.getAnnotation(CacheControlHeader.class); 
     if (cch == null) { 
      return NO_CACHE_FILTER; 
     } else { 
      return Collections.<ResourceFilter>singletonList(new CacheResponseFilter(cch.value())); 
     } 
    } 

    private static class CacheResponseFilter implements ResourceFilter, ContainerResponseFilter { 
     private final String headerValue; 

     CacheResponseFilter(String headerValue) { 
      this.headerValue = headerValue; 
     } 

     @Override 
     public ContainerRequestFilter getRequestFilter() { 
      return null; 
     } 

     @Override 
     public ContainerResponseFilter getResponseFilter() { 
      return this; 
     } 

     @Override 
     public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { 
      // attache Cache Control header to each response based on the annotation value 
      response.getHttpHeaders().putSingle(HttpHeaders.CACHE_CONTROL, headerValue); 
      return response; 
     } 
    } 
} 

açıklama şöyle olabilir:

ResourceFilterFactory Jersey tanımına aşağıdaki init param ekleyerek başvuruda kayıtlı edilebilir
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface CacheControlHeader { 
    String value(); 
} 

web.xml sunucu uygulaması: @ firması tarafından çözelti dayanarak

<init-param> 
    <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name> 
    <param-value>package.name.CacheFilterFactory</param-value> 
</init-param> 
+0

Bu kadar güzel topladığınız için teşekkürler. Bunu kendi başıma hallettim, ama bu hak, bunu yapmak için "Doğru Yol" u mükemmel bir şekilde özetliyor. – Pete

+0

Her biri için açıklama eklemek zorunda kalmadan, tüm yöntemler için önbellek önbelleği denetimini ayarlamanın bir yolu var mı? –

+0

[Jersey İle Ek Açıklamaları Kullanarak Önbellek Denetimi] (http://alex.nederlof.com/blog/2013/07/28/caching-using-annotations-with-jersey/) çok daha temiz ve eksiksiz –

13

martin-matula iki Önbellek açıklamaları hazırlandı. Önbelleğe alma için bir @NoCache ve belirli bir önbellekleme için bir @CacheMaxAge. Eğer et saniye kendini hesaplamak zorunda kalmamak CacheMaxAge iki argüman alır:

@GET 
@CacheMaxAge(time = 10, unit = TimeUnit.MINUTES) 
@Path("/awesome") 
public String returnSomethingAwesome() { 
    ... 
} 

ResourceFilter şimdi bu (böylece diğer önbelleğe alma mekanizmaları çalışmaya devam) varsayılan olarak müdahale etmeyen yöntemi oluşturmak vardır:

@Override 
public List<ResourceFilter> create(AbstractMethod am) { 
    if (am.isAnnotationPresent(CacheMaxAge.class)) { 
     CacheMaxAge maxAge = am.getAnnotation(CacheMaxAge.class); 
     return newCacheFilter("max-age: " + maxAge.unit().toSeconds(maxAge.time())); 
    } else if (am.isAnnotationPresent(NoCache.class)) { 
     return newCacheFilter("no-cache"); 
    } else { 
     return Collections.emptyList(); 
    } 
} 

private List<ResourceFilter> newCacheFilter(String content) { 
    return Collections 
      .<ResourceFilter> singletonList(new CacheResponseFilter(content)); 
} 

in my blogpost tam çözümünü görebilirsiniz.

Çözüm Martin için teşekkürler!

6

@ martin-matula'nın çözümü, ResourceFilterFactory ve ResourceFilter kaldırıldığı için JAX-RS 2.0/Jersey 2.x ile çalışmaz. Çözelti, aşağıdaki gibi JAX-RS 2.0'a uyarlanabilir.

Ek Açıklama:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface CacheControlHeader { 
    String value(); 
} 

DynamicFeature:

@Provider 
public class CacheFilterFactory implements DynamicFeature { 

    private static final CacheResponseFilter NO_CACHE_FILTER = 
      new CacheResponseFilter("no-cache"); 

    @Override 
    public void configure(ResourceInfo resourceInfo, 
         FeatureContext featureContext) { 

    CacheControlHeader cch = resourceInfo.getResourceMethod() 
      .getAnnotation(CacheControlHeader.class); 
    if (cch == null) { 
     featureContext.register(NO_CACHE_FILTER); 
    } else { 
     featureContext.register(new CacheResponseFilter(cch.value())); 
    } 
    } 

    private static class CacheResponseFilter implements ContainerResponseFilter { 
    private final String headerValue; 

    CacheResponseFilter(String headerValue) { 
     this.headerValue = headerValue; 
    } 

    @Override 
    public void filter(ContainerRequestContext containerRequestContext, 
         ContainerResponseContext containerResponseContext) { 
     // attache Cache Control header to each response 
     // based on the annotation value      
     containerResponseContext 
       .getHeaders() 
       .putSingle(HttpHeaders.CACHE_CONTROL, headerValue); 
    } 

    } 
} 

CacheFilterFactory Jersey kayıtlı olması gerekmektedir. Dropwizard aracılığıyla - environment.jersey(). Register() kullanarak yapıyorum - ama bağımsız sistemlerde bu örneğin Örneğin web.xml'de aşağıdakileri tanımlayarak @Provider ek açıklamaları için sınıflarınızı taramasını sağlayarak bunu yapabilirim :

<servlet> 
    <servlet-name>my.package.MyApplication</servlet-name> 
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> 

    <!-- Register resources and providers under my.package. --> 
    <init-param> 
     <param-name>jersey.config.server.provider.packages</param-name> 
     <param-value>my.package</param-value> 
    </init-param> 
</servlet> 

bileşenlerini kaydetme hakkında daha fazla bilgi için this post bakınız.

0

Önbelleğe almayı devre dışı bırakabilen bir ek açıklama buldum. Eğer API için aşağıdaki ek açıklama kullanabilirsiniz:

@CacheControl(noCache = true) 

Ref: Ben belirli bir tek Tepki bunu yapabilir Jersey Annotation for cache control

+0

İlkbaharda bir org.springframework.http.CacheControl sınıfına bağlanıyorsunuz, bu da bir ek açıklama değil. Muhtemelen bir ek açıklama olmayan javax.ws.rs.core.CacheControl. – FelixJongleur42