`
zzc1684
  • 浏览: 1222876 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

JAX-RS入门 十二: 可伸缩的JAX-RS应用

阅读更多

一、HTTP Caching

 

HTTP1.0中定义了Expires来指定cache在浏览器的生命时长。例如:

Html代码 复制代码 收藏代码
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/xml   
  3. Expires: Tue, 15 May 2011 16:00 GMT   
  4.   
  5. <Customer id="1">...</Customers>  

缓存的数据直到2011年5月15有效。

 

在JAX-RS中使用javax.ws.rs.core.Response对象来设置有效期:

 

 

Java代码 复制代码 收藏代码
  1. @Path("{id}")   
  2. @GET  
  3. @Produces("application/xml")   
  4. public Response getCustomer(@PathParam("id"int id) {   
  5.     Customer cust = findCustomer(id);   
  6.     ResponseBuilder builder = Response.ok(cust, "application/xml");   
  7.     Date date = Calendar.getInstance().set(2010515160);   
  8.     builder.expires(date);   
  9.     return builder.build();   
  10. }   

HTTP1.1中重新设计了缓存语法。通过使用Cache-Control来对cache进行控制,其中的值以逗号分隔。它包括:

  • private
    用于指定当且仅有Client才能缓存这个数据
  • public
    指定在 请求/响应 链中的任何环节都可以缓存数据
  • no-cache
    这个指令用于指示数据不应该缓存或者除非数据被重新验证过,否则不能被用于再次请求
  • no-store
    通过缓存数据都被缓存了硬盘中,以使用得下次可以;这个指令表示不要将缓存存在本地。
  • no-transform
    有时缓存会被自动进行转换以节省内存或者带宽,例如压缩图像。no-transform用于指定不允许进行数据转换
  • max-age
    max-age用于指示缓存的有效期;如果max-age和Expires同时指定,则max-age有效
  • s-maxage
    用于指定缓存在一个共享的,中间节点的最大生命期。

例如:

Java代码 复制代码 收藏代码
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/xml   
  3. Cache-Control: private, no-store, max-age=300  
  4.   
  5. <customers>...</customers>   

与Cache-Control对应的,JAX-RS提供了javax.ws.rs.core.CacheControl类来表示Cache-Control头:

Java代码 复制代码 收藏代码
  1. public class CacheControl {   
  2.     public CacheControl() {...}   
  3.   
  4.     public static CacheControl valueOf(String value)   
  5.     throws IllegalArgumentException {...}   
  6.     public boolean isMustRevalidate() {...}   
  7.     public void setMustRevalidate(boolean mustRevalidate) {...}   
  8.     public boolean isProxyRevalidate() {...}   
  9.     public void setProxyRevalidate(boolean proxyRevalidate) {...}   
  10.     public int getMaxAge() {...}   
  11.     public void setMaxAge(int maxAge) {...}   
  12.     public int getSMaxAge() {...}   
  13.     public void setSMaxAge(int sMaxAge) {...}   
  14.     public List<String> getNoCacheFields() {...}   
  15.     public void setNoCache(boolean noCache) {...}   
  16.     public boolean isNoCache() {...}   
  17.     public boolean isPrivate() {...}   
  18.     public List<String> getPrivateFields() {...}   
  19.     public void setPrivate(boolean _private) {...}   
  20.     public boolean isNoTransform() {...}   
  21.     public void setNoTransform(boolean noTransform) {...}   
  22.     public boolean isNoStore() {...}   
  23.     public void setNoStore(boolean noStore) {...}   
  24.     public Map<String, String> getCacheExtension() {...}   
  25. }   

在ResponseBuilder类中调用callControl()设置返回的Cache-Control:

Java代码 复制代码 收藏代码
  1. @Path("{id}")   
  2. @GET  
  3. @Produces("application/xml")   
  4. public Response getCustomer(@PathParam("id"int id) {   
  5.     Customer cust = findCustomer(id);   
  6.     CacheControl cc = new CacheControl();   
  7.     cc.setMaxAge(300);   
  8.     cc.setPrivate(true);   
  9.     cc.setNoStore(true);   
  10.     ResponseBuilder builder = Response.ok(cust, "application/xml");   
  11.     builder.cacheControl(cc);   
  12.     return builder.build();   
  13. }   

二、重验证和条件GET

 

另一个和cache有关的就是当cache变得陈旧的时候,缓存端能够询问服务端缓存的数据是否仍然有效,这叫做revalidation。为了执行revalidation,客户端需要从服务器端取得一些缓存数据的额外的信息,服务端在最初的响应里会发回一个Last-Modified与/或ETag头。

 

* Last-Modified

 

Last-Modified头表示服务端发回数据的一个时间戳。例如:

Java代码 复制代码 收藏代码
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/xml   
  3. Cache-Control: max-age=1000  
  4. Last-Modified: Tue, 15 May 2009 09:56 EST   
  5.   
  6. <customer id = "1">..</customer>  

以上,最初的响应的有效期是1000秒,并且时间戳是2009,5,15,9点56。如果客户端支持重新验证,它会存储这个时候戳到缓存数据中。1000稍以后,客户端可以选择重新验证缓存。要重新验证,它需要发送一个条件(conditional)GET请求,并且传递一个If-Modified-Since头信息,If-Modified-Since的值即是Last-Modified的值。例如:

Java代码 复制代码 收藏代码
  1. GET /customers/123 HTTP/1.1  
  2. If-Modified-Since: Tue, 15 May 2009 09:56 EST   

然后服务器会判断数据是否有变化,如果有,则返回一个200, 'OK'的响应,并发回新的响应体;如果没有改变,则返回304, 'Not Modified',和一个空的响应体。这两种情况下都需要发送新的Cache-Control和Last-Modified头。

 

* ETag

 

ETag是用来表示数据版本的、假设唯一的某个标识。它的值是任一一个以引用括起的字符串,通常是MD5 哈希值。 例如:

Html代码 复制代码 收藏代码
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/xml   
  3. Cache-Control: max-age=1000  
  4. ETag: "3141271342554322343200"   
  5.   
  6. <customer id="123">...</customer>   

类似于Last-Modified头,如果客户端缓存了这个响应体,则也应该缓存ETag的值。1000秒以后,客户端需要执行一个重验证请求,其中包含一个If-None-Match的请求头:

Html代码 复制代码 收藏代码
  1. GET /customers/123 HTTP/1.1   
  2. If-None-Match: "3141271342554322343200"  

当服务器端收到这个GET请求时,它就会试图比较当前resource的ETag值和传入的If-None-Match的值,如果不成功,则返回200, 'OK'和一个新的响应体;否则返回304和'Not Modified’和一个空的响应体。

 

最后关于ETag有两种类型:strong和weak:

  • 一个strong的ETag:资源的任何变化都会引起ETag的变化
  • 一个weak的ETag:只有资源显著的变化才变化

例如,一个weak的ETag:

Java代码 复制代码 收藏代码
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/xml   
  3. Cache-Control: max-age=1000  
  4. ETag: W/"3141271342554322343200"  
  5.   
  6. <customer id="123">...</customer>   

 对应于ETag的JAX-RS类是javax.ws.rs.core.EntityTag:

Java代码 复制代码 收藏代码
  1. public class EntityTag {   
  2.     public EntityTag(String value) {...}   
  3.     public EntityTag(String value, boolean weak) {...}   
  4.     public static EntityTag valueOf(String value)   
  5.         throws IllegalArgumentException {...}   
  6.     public boolean isWeak() {...}   
  7.     public String getValue() {...}   
  8. }   

 * JAX-RS和条件GET

为了计算上面的验证条件,JAX-RS提供了一个帮助类javax.ws.rs.core.Request:

Java代码 复制代码 收藏代码
  1. public interface Request {   
  2.     ...   
  3.     ResponseBuilder evaluatePreconditions(EntityTag eTag);   
  4.     ResponseBuilder evaluatePreconditions(Date lastModified);   
  5.     ResponseBuilder evaluatePreconditions(Date lastModified, EntityTag eTag);   
  6. }   

重载的evaludatePreconditions()方法需要一个javax.ws.rs.core.EntityTag和/或java.util.Date对象,表达ETag和最后修改时间(Last-Modified)。这些值是最新的、当前的,然后把它们同传入的请求参数If-Not-Modified和If-None-Match对象。如果不匹配则返回200,'OK'和响应体,或者返回304,'Not Modified'和空响应体:

Java代码 复制代码 收藏代码
  1. @Path("/customers")   
  2. public class CustomerResource {   
  3.   
  4.     @Path("{id}")   
  5.     @GET  
  6.     @Produces("application/xml")   
  7.     public Response getCustomer(@PathParam("id"int id,   
  8.             @Context Request request) {   
  9.   
  10.         Customer cust = findCustomer(id);   
  11.         EntityTag tag = new EntityTag(   
  12.         Integer.toString(cust.hashCode()));   
  13.         CacheControl cc = new CacheControl();   
  14.         cc.setMaxAge(1000);   
  15.         ResponseBuilder builder = request.evaluatePreconditions(tag);   
  16.         if (builder != null) {   
  17.             builder.cacheControl(cc);   
  18.             return builder.build();   
  19.         }   
  20.         // Preconditions not met!   
  21.         builder = Response.ok(cust, "application/xml");   
  22.         builder.cacheControl(cc);   
  23.         builder.tag(tag);   
  24.         return builder.build();   
  25.     }   
  26. }   

三、并发(Concurrency)

 

当需要更新Server上的某个数据时,通常就需要面对并发的问题了,因为很有可能有多个人同时在更新同一个信息。

 

HTTP规范通过使用有条件的PUT或POST请求来解决这个问题,有点类似于有条件GET请求。首先客户端取得数据:

Html代码 复制代码 收藏代码
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/xml   
  3. Cache-Control: max-age=1000  
  4. ETag: "3141271342554322343200"   
  5. Last-Modified: Tue, 15 May 2009 09:56 EST   
  6.   
  7. <customer id="123">...</customer>  

为了带条件的更新,我们需要用到ETag或Last-Modified头,这些信息用于告诉服务端我们需要更新的哪个版本。当我们做PUT或POST请求时,这些信息会随同If-Match或If-Unmodified-Since一同发送出去,其中If-Match信息的值是ETag;If-Unmodified-Since的值是Last-Modified。因此上面GET对应的更新请求可能是:

Html代码 复制代码 收藏代码
  1. PUT /customers/123 HTTP/1.1   
  2. If-Match: "3141271342554322343200"   
  3. If-Unmodified-Since: Tue, 15 May 2009 09:56 EST   
  4. Content-Type: application/xml   
  5.   
  6. <customer id="123">...</customer>  

可以发送If-Match或If-Unmodified-Since中的任何一个。当Server收到这个请求时,就会去检查当前的ETag是否匹配If-Match或当前的时间戳是否匹配If-Unmodified-Since头。如果这些条件都不满足,则返回412, 'Precondition Failed'响应,用于告诉客户端当前数据已经被修改过,请重试;如果条件满足,则执行更新,并返回成功的结果。

 

* JAX-RS和条件更新

 

 和读取数据一样,还是要用到Request.evaluatePreconditions()方法,例如:

Java代码 复制代码 收藏代码
  1. @Path("/customers")   
  2. public class CustomerResource {   
  3.   
  4.     @Path("{id}")   
  5.     @PUT  
  6.     @Consumes("application/xml")   
  7.     public Response updateCustomer(@PathParam("id"int id,   
  8.         @Context Request request) {   
  9.         Customer cust = findCustomer(id);   
  10.         EntityTag tag = new EntityTag(   
  11.         Integer.toString(cust.hashCode()));   
  12.         Date timestamp = ...; // get the timestampe   
  13.         ResponseBuilder builder =   
  14.         request.evaluatePreconditions(timestamp, tag);   
  15.         if (builder != null) {   
  16.             // Preconditions not met!   
  17.             return builder.build();   
  18.         }   
  19.         //... perform the update ...   
  20.         builder = Response.noContent();   
  21.         return builder.build();   
  22.     }   
  23. }  
分享到:
评论

相关推荐

    Spring MVC与JAX-RS比较与分析

    这个架构原则提升了万维网的可伸缩性,无论何种应用都能从该原则中受益无穷。 JAX-RS(JSR 311)指的是Java API for RESTful Web Services,Roy Fielding也参与了JAX-RS的制订,他在自己的博士论文中定义了REST。...

    Restful java with jax-rs

    ### RESTful Java with JAX-RS #### 一、REST与HTTP的复兴 在《RESTful Java with JAX-RS》这本书中,作者Bill Burke强调了REST架构的重要性及其与HTTP协议之间的紧密联系。REST(Representational State Transfer...

    RESTful Java FOR Jax-RS

    本书由Bill Burke撰写,由O'Reilly Media出版,是专业开发人员和架构师了解REST架构原则及JAX-RS应用实践的宝贵资源。 ### RESTful架构原则 REST(Representational State Transfer)是一种软件架构风格,最初由...

    jboss-jaxrs-api_1.1_spec-1.0.0.Final.zip

    【标题】"jbosss-jaxrs-api_1.1_spec-1.0.0.Final.zip" 提供的是Java企业版(Java EE)中的一部分关键规范,即Java API for RESTful Web Services (JAX-RS) 1.1的实现。JAX-RS是Java平台上的一个标准接口,它允许...

    Jax-rs_JWT_JSF:这是一个用JWT和JSF使用JAX-RS的示例项目

    这个示例项目为开发者提供了一个实用的学习资源,展示了如何在实际应用中集成JAX-RS、JWT和JSF,帮助他们理解如何在Java环境中构建安全、高效的Web服务。通过深入研究和实践,开发者可以提升自己的技能,掌握现代Web...

    使用Eclipse开发基于SpringBoot+JAX-RS的Restful服务.docx

    在本文中,我们将深入探讨如何使用Eclipse开发一个基于Spring Boot和JAX-RS的Restful服务。首先,让我们理解一下这两个关键...持续学习和实践Spring Boot和JAX-RS,能够让你更熟练地构建高效、可维护的RESTful服务。

    restful_simple_example:带有 Maven、JAX-RS、JAXB、EASTeasy 的 RESTful Web 服务的简单示例 ..

    REST(Representational State Transfer)是一种架构风格,强调简洁、可伸缩性和基于HTTP协议的设计。本项目"restful_simple_example"是一个简单的RESTful Web服务示例,利用了Java生态中的几个关键组件:Maven、JAX...

    REST介绍文档

    根据给定的文件信息,以下是对RESTful Java与JAX-RS相关知识点的详细解析: ...通过理解和应用REST原则,结合JAX-RS的灵活性和易用性,开发人员可以构建出高性能、可扩展且易于集成的服务,充分利用Web的固有优势。

    Java Restful Web Service,edition2.代码

    通过分析和学习这个代码库,开发者可以深入了解如何使用Java和JAX-RS 2.0构建RESTful Web服务,从而提高自己在构建可伸缩、高性能Web应用方面的能力。同时,这个第二版的代码可能包含了第一版中的改进和新特性,对于...

    openshift-tika-cartridge:一个包含Apache Tika JAXRS服务器的OpenShift弹药筒

    OpenShift Apache Tika服务器墨盒OpenShift的盒式磁带,提供对Apache Tika JAXRS服务器的访问。 这是为2014年4月在苏格兰JBUG上的演讲准备的。安装要安装此墨盒,请在创建应用程序时使用墨盒反射器 rhc create-app ...

    restJersey:使用Jersey JAX-RS的REST

    REST(Representational State Transfer)是一种网络应用程序的设计风格和开发方式,主要基于HTTP协议,用于构建可伸缩、高性能的Web服务。RESTful API的设计原则是将资源作为URI(Uniform Resource Identifier),...

    Restlet开发实例

    REST是一种轻量级的架构风格,广泛应用于Web应用程序的开发,以提高性能、可伸缩性和可维护性。本系列的开发实例将带你深入理解并掌握Restlet框架的使用,从基础的JAX-RS实现到高级的Component和Application结构,再...

    RESTful Java Web Services (2009).pdf

    - **Jersey's JAX-RS**:基于Java API for RESTful Web Services (JAX-RS) 的开源实现,提供了丰富的API来构建RESTful服务。 - **Restlet's Lightweight REST**:一个轻量级的REST客户端和服务端框架,适用于构建...

    soen487-restful-repository:SOEN 487团队项目

    这些原则确保了系统的可伸缩性和灵活性。 2. **JAX-RS**:JAX-RS是Java EE平台的一部分,用于简化开发RESTful Web服务。它通过注解如`@Path`, `@GET`, `@POST`, `@PUT`, `@DELETE`等来声明HTTP方法和资源路径。 3....

    RESTFUL JAVA

    RESTful Java不仅对于构建现代Web服务至关重要,而且对于提高系统的可伸缩性、可维护性和互操作性具有重要意义。通过遵循REST的原则,开发者可以创建出更为简洁、易于理解和扩展的服务。 **RESTful架构原则:** 1. ...

    rest-with-application:其余项目的示例扩展了Application类(在weblogic 12c中测试)

    在IT行业中,REST(Representational State Transfer)是一种广泛采用的Web服务架构风格,用于构建可伸缩、高性能的分布式系统。本项目“rest-with-application”是针对RESTful服务的一个示例,它扩展了`Application...

    Java EE 7 Developer Handbook.pdf

    - **社交媒体应用**:介绍如何利用WebSocket和JAX-RS创建交互式的社交网络。 - **企业内部管理系统**:探讨如何通过Java EE 7的技术栈实现高效的内部流程管理。 #### 六、最佳实践 - **代码复用**:通过模块化设计...

    RESTful-Java-Web-Services-Third-Edition:RESTful Java Web服务第三版,由Packt发行

    本书涵盖以下激动人心的功能: 向您介绍RESTful软件架构风格和REST API设计原则利用JSR 353 API,JSR 374 API,JSR 367 API和Jackson API进行JSON处理利用JAX-RS 2.1 API构建可移植的RESTful Web API 使用Jersey和...

    cxf webservice restful实现

    - 配置CXF服务:在Spring配置文件中,使用`&lt;jaxrs:server&gt;`元素声明CXF服务,并通过`&lt;jaxrs:serviceBean&gt;`引用服务实现类。 2. **客户端调用**: - 创建服务代理:使用CXF的`JAXRSClientFactory`,可以生成客户端...

Global site tag (gtag.js) - Google Analytics