这篇文章(通过一个简单的示例)说明了如何使用CDI Producers使其在RESTful服务中利用缓存控制语义更加容易
与HTTP 1.0中可用的Expires标头相比, HTTP 1.1中添加了Cache-Control标头,这是急需的改进。 RESTful Web服务可以利用此标头来扩展其应用程序并使它们更有效,例如,如果您可以缓存先前请求的响应,那么显然,如果您确定对以下内容,则无需再次向服务器发出相同的请求您缓存的数据不是陈旧的事实!
JAX-RS有何帮助?
自其初始(1.0)版本以来, JAX-RS就已经支持Cache-Control标头。 CacheControl类表示现实世界中的Cache-Control HTTP标头,并提供了通过简单的setter方法配置标头的功能。 JAX-RS 2.0 javadocs中有关CacheControl类的更多信息
那么我该如何使用
只需返回一个Response对象,即可围绕它包装 CacheControl类的实例。
@Path("/testcache")
public class RESTfulResource {@GET@Produces("text/plain")public Response find(){CacheControl cc = new CacheControl();cc.setMaxAge(20);return Response.ok(UUID.randomUUID().toString()).cacheControl(cc).build();}
}
尽管这对于单个方法来说相对方便,但是重复创建和返回CacheControl对象可能会激怒多个方法
CDI生产者来抢救!
CDI生产者可以帮助注入类的实例,这些类在技术上不是Bean (按照严格的定义),或者对于您无法控制的类,要使用范围和限定符进行修饰。
这个想法是为了
- 有一个自定义注释( @CacheControlConfig )来定义Cache-Control标头的默认值,并在您要覆盖它时提供灵活性
@Retention(RUNTIME) @Target({FIELD, PARAMETER}) public @interface CachControlConfig {public boolean isPrivate() default true;public boolean noCache() default false;public boolean noStore() default false;public boolean noTransform() default true;public boolean mustRevalidate() default true;public boolean proxyRevalidate() default false;public int maxAge() default 0;public int sMaxAge() default 0;}
- 只需使用CDI Producer通过使用InjectionPoint对象(由CDI高兴地注入!)来创建CacheControl类的实例,具体取决于注释参数
public class CacheControlFactory {@Producespublic CacheControl get(InjectionPoint ip) {CachControlConfig ccConfig = ip.getAnnotated().getAnnotation(CachControlConfig.class);CacheControl cc = null;if (ccConfig != null) {cc = new CacheControl();cc.setMaxAge(ccConfig.maxAge());cc.setMustRevalidate(ccConfig.mustRevalidate());cc.setNoCache(ccConfig.noCache());cc.setNoStore(ccConfig.noStore());cc.setNoTransform(ccConfig.noTransform());cc.setPrivate(ccConfig.isPrivate());cc.setProxyRevalidate(ccConfig.proxyRevalidate());cc.setSMaxAge(ccConfig.sMaxAge());}return cc;} }
- 只需将 CacheControl实例注入您的REST资源类中,并在您的方法中使用它
@Path("/testcache") public class RESTfulResource {@Inject@CachControlConfig(maxAge = 20)CacheControl cc;@GET@Produces("text/plain")public Response find() {return Response.ok(UUID.randomUUID().toString()).cacheControl(cc).build();} }
其他想法
- 在这种情况下,产生的CacheControl实例的作用域为@Dependent,即它将与注入它的类一起生存和死亡。 在这种情况下,由于JAX-RS容器为每个客户端请求创建了一个新实例,因此JAX-RS资源本身是RequestScoped (默认),因此将与每个HTTP请求一起创建注入的CacheControl实例的新实例。
- 您还可以引入CDI限定词以进一步缩小范围并考虑极端情况
- 您可能会认为,使用JAX-RS过滤器可以实现相同的目的。 那是正确的。 但是您需要手动设置Cache-Control标头(在可变的MultivaluedMap中),并且逻辑不够灵活,无法解决不同情况下的不同Cache-Control配置
实验结果
使用NetBeans IDE播放此示例(推荐)
- 部署WAR并浏览到http:// localhost:8080 / JAX-RS-Caching-CDI / testcache
- 随机字符串,将被缓存20秒 (根据@CacheControl注释的配置)
- 对相同URL的GET请求不会导致服务器端REST服务的调用。 浏览器将返回缓存的值。
尽管代码很简单,但是如果您觉得很懒,可以从这里获取(maven)项目并在其中玩转
玩得开心!
翻译自: https://www.javacodegeeks.com/2015/02/simplifying-jax-rs-caching-with-cdi.html