2012-06-07 15 views
20

एक विश्वसनीय वेब सेवा लिखते समय, यदि मैं अपने क्लाइंट (वर्तमान में एक .NET मोटी क्लाइंट) पर किसी भी प्रकार की कैशिंग सक्षम करता हूं तो मुझे समस्याएं आ रही हैं। डिफ़ॉल्ट रूप से जर्सी किसी भी तरह का कैश नियंत्रण शीर्षलेख नहीं भेज रहा है, इसलिए क्लाइंट स्वचालित रूप से अधिकांश पृष्ठों को कैश कर रहा है (जो वैध व्यवहार प्रतीत होता है)।जर्सी: डिफ़ॉल्ट कैश नियंत्रण नो-कैश

मैं डिफ़ॉल्ट रूप से जर्सी को "नो-कैश" का कैश नियंत्रण भेजना चाहता हूं, और फिर विशेष प्रतिक्रियाओं में कैश नियंत्रण को ओवरराइड करना चाहते हैं।

क्या जर्सी के साथ ऐसा करने का कोई तरीका है?

मुझे पता चला है कि रीस्टेसी में पूरे वर्ग की सेटिंग निर्दिष्ट करने के लिए @ नोचैच एनोटेशन का उपयोग करने की क्षमता है, लेकिन मुझे जर्सी के समान कुछ नहीं मिला है।

उत्तर

23

जर्सी के साथ रिसोर्सफिल्टर फैक्टरी का उपयोग करके यह आसान है - आप कैश नियंत्रण सेटिंग्स सेट करने के लिए अपने तरीकों से संलग्न कोई कस्टम एनोटेशन बना सकते हैं। एप्लिकेशनफिल्टर फैक्ट्रीज को प्रत्येक खोजी संसाधन विधि के लिए बुलाया जाता है जब एप्लिकेशन प्रारंभ होता है - आपके संसाधनफिल्टरफ़ैक्टरी में आप यह जांच सकते हैं कि विधि में आपके @ कैशकंट्रोल हैडर एनोटेशन (या जो भी आप इसे कॉल करना चाहते हैं) - यदि नहीं, तो प्रतिक्रिया फ़िल्टर वापस करें जो "नो-कैश" "प्रतिक्रिया के लिए निर्देश, अन्यथा यह एनोटेशन से सेटिंग्स का उपयोग करना चाहिए। यहाँ कैसे करना है का एक उदाहरण है कि:

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; 
     } 
    } 
} 

एनोटेशन इस तरह दिख सकता:

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

ResourceFilterFactory अपने आवेदन में जर्सी की परिभाषा के लिए निम्न init परम जोड़कर पंजीकृत किया जा सकता web.xml में सर्वलेट:

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

इसे बहुत अच्छी तरह से संक्षेप में करने के लिए धन्यवाद। मैंने इसे अपने आप से फंसाया था, लेकिन यह सही करने के लिए पूरी तरह से "सही रास्ता" का सारांश देता है। – Pete

+0

क्या प्रत्येक विधि के लिए एनोटेशन जोड़ने के बिना सभी विधियों के लिए कैश नियंत्रण को कैश नियंत्रण सेट करने का कोई तरीका है? –

+0

[जर्सी के साथ एनोटेशन का उपयोग करके कैश-कंट्रोल] (http://alex.nederlof.com/blog/2013/07/28/caching-using-annotations-with-jersey/) बहुत साफ और पूर्ण –

1

मुझे लगता है कि आप

isNoCache(true) 

जो ब्राउज़र में कैशिंग बंद हो जाएगा उपयोग कर सकते हैं।

देखें:

http://jersey.java.net/nonav/apidocs/1.12/jersey/javax/ws/rs/core/CacheControl.html#isNoCache%28%29

आशा इस मदद करता है।

+0

हाँ, मैं ऐसा कर सकते हैं किसी दिए गए एक रिस्पांस पर, मैं एक उच्च/अधिक सामान्य स्तर पर कुछ है करने की उम्मीद कर रहा था। – Pete

13

@ मार्टिन-मैटुला द्वारा समाधान के आधार पर मैंने दो कैश एनोटेशन बनाए। विशिष्ट कैशिंग के लिए एक @NoCache कोई कैशिंग नहीं है और एक @CacheMaxAge है। CacheMaxAge दो तर्क लेता है ताकि आप सेकंड में अपने आप की गणना करने की जरूरत नहीं:

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

ResourceFilter अब इस विधि कि डिफ़ॉल्ट रूप से हस्तक्षेप नहीं करता है बनाने के (ताकि अन्य कैशिंग प्रणाली काम कर रखना) है:

@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 देख सकते हैं।

समाधान मार्टिन के लिए धन्यवाद!

6

@ मार्टिन-मैटुला का समाधान जेएक्स-आरएस 2.0/जर्सी 2.x के साथ काम नहीं करता है क्योंकि संसाधनफिल्टर फैक्ट्री और रिसोर्सफिल्टर को हटा दिया गया है। इस प्रकार समाधान को जेएक्स-आरएस 2.0 में अनुकूलित किया जा सकता है।

एनोटेशन:

@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 जर्सी के साथ पंजीकृत किया जाना चाहिए। मैं Dropwizard के माध्यम से कर रहा हूं - पर्यावरण.जर्सी()। रजिस्टर() - लेकिन स्टैंडअलोन सिस्टम पर मैं समझता हूं कि यह उदाहरण के लिए किया जा सकता है उदाहरण के लिए जर्सी को अपने वेब.एक्सएमएल में निम्नलिखित परिभाषित करके @Provider एनोटेशन के लिए अपनी कक्षाओं को स्कैन करने दें। :

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

घटकों पंजीकरण के बारे में अधिक जानकारी के लिए this post देखें।

0

मुझे एक एनोटेशन मिला जो कैशिंग को अक्षम कर सकता है। आप अपने एपीआई के लिए निम्नलिखित एनोटेशन का उपयोग कर सकते हैं:

@CacheControl(noCache = true) 

रेफरी: Jersey Annotation for cache control

+0

आप स्प्रिंग से कक्षा g.springframework.http.CacheControl से लिंक कर रहे हैं जो या तो एनोटेशन नहीं है। आप शायद javax.ws.rs.core.CacheControl का मतलब है जो एक एनोटेशन भी नहीं है। – FelixJongleur42

संबंधित मुद्दे