`

Jersey2.x对REST请求处理流程的分析

阅读更多

Jersey2.x对REST请求处理流程的分析

一个REST请求,始于一个RESTful Web Service资源的地址,终于一个可接受的对资源的表述(比如JSON)。

因此,流程分析的关键点有2个:

  • 将请求地址对应到资源类的相应方法上,并触发该方法。
  • 将返回值转换成请求所需要的表述,并返回给客户端。

我们使用Eclipse的断点调试服务器端(代码对应本例https://github.com/feuyeux/jax-rs2-guide/),使用cURL脚本作为客户端。

1 cURL测试

curl -H "Accept:application/json" http://localhost:8080/simple-service-webapp-spring-jpa-jquery/webapi/books/book?id=1

该脚本发送了一个REST GET请求,地址是:

http://localhost:8080/simple-service-webapp-spring-jpa-jquery/webapi/books/book?id=1

对应的服务器端方法是:

com.example.resource.BookResource.getBookByQuery(Integer)

要求返回的类型是JSON:

Accept:application/json

2 Jersey2.x流程

2.1 请求地址到REST方法

2.1.1 ServletContainer.service

ServletContainer.service(HttpServletRequest, HttpServletResponse) line: 248

  • baseUri http://localhost:8080/simple-service-webapp-spring-jpa-jquery/webapi/
  • requestUri http://localhost:8080/simple-service-webapp-spring-jpa-jquery/webapi/books/book?id=1

ServletContainer是HttpServlet的子类,位于Jersey容器包(.m2\repository\org\glassfish\jersey\containers\jersey-container-servlet-core\2.2\jersey-container-servlet-core-2.2.jar)。我们知道,Servlet的service方法是请求的入口,作为子类,HTTP任何方法的请求都要先经过该类的service方法。

断点堆栈中,重要的两个变量是请求地址信息的baseUri和requestUri。

dependencies 

Jersey包依赖关系图

ServletContainer.service(URI, URI, HttpServletRequest, HttpServletResponse) line: 372

  • requestContext.header {user-agent=[curl/7.26.0], host=[localhost:8080], accept=[application/json]}

在容器层级,请求上下文变量除了包括请求地址信息外,还包括请求头信息。这里我们关注accept信息。

2.1.2 对应方法

ApplicationHandler.handle(ContainerRequest) line: 982

ServerRuntime.process(ContainerRequest) line: 211 final Runnable task

new Runnable() {
 public void run() {
  final ContainerRequest data = Stages.process(request, requestProcessingRoot, endpointRef);
  final Endpoint endpoint = endpointRef.get();
  • endpoint ResourceMethodInvoker (id=2553)
    public com.example.domain.Book com.example.resource.BookResource.getBookByQuery(java.lang.Integer)

从上面的代码片段,可以看到请求被对应到了一个Endpoint对象,该对象是一个资源方法Invoker,从断点堆栈中可以看到,其内容就是我们期待的那个方法,此后的invoke将调用这个对应REST请求的处理方法。

2.1.3 调用方法

ResourceMethodInvoker.invoke(ContainerRequest, Object) line: 353
dispatcher.dispatch(resource, requestContext);

JavaResourceMethodDispatcherProvider$TypeOutInvoker(AbstractJavaResourceMethodDispatcher).invoke(Object, Object...) line: 158
invokeMethodAction.run();

ResourceMethodInvocationHandlerFactory$1.invoke(Object, Method, Object[]) line: 81

从堆栈中可以轻松定位这个方法:**BookResource.getBookByQuery(Integer) line: 71**

到此,请求地址到方法调用的流程就结束了。在处理业务逻辑方法BookResource.getBookByQuery后,Jersey将开始处理响应信息。

2.2 REST方法到表述

JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(Object, Request) line: 198

  • o Book (id=2686)
  • Response response = Response.ok().entity(o).build();

REST请求的返回信息应包括表述信息和HTTP响应代码(通常一个成功的请求应该得到200 OK)。这就是上面代码所做的事情。在设置好response的entity后,需要将该entity对象转化成请求所接受的表述,流程如下。

2.2.1 写向response

ServerRuntime$Responder.process(ContainerResponse) line: 351ServerRuntime$Responder.writeResponse(ContainerResponse) line: 486

  • entity Book (id=7076)
  • executor WriterInterceptorExecutor (id=7125)

从上面的堆栈中可以看到,这个阶段重点的两个对象是返回对象和写处理对象,就是使用后者将前者恰当地写入response中。

2.2.2 JSON表述

REST的表述不局限于JSON,这里我们以JSON作为常用的表述类型为例,来讨论Jersey的表述处理。 Jersey对JSON的支持有4种方式,在第3章会有详细的讲解,本例使用的是EclipseLink项目的MOXy。其底层依赖是JPA的实现之一(另一个著名的JPA实现是JBoss项目下大名鼎鼎的Hibernate)。

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
        <version>${jersey.version}</version>
    </dependency>

moxy

MOXy依赖关系图

在下面的堆栈中,可以看到JAXB的身影,因为MOXy同样实现了JAXB,其内部实现是以XML的Marshal方式处理对象(OXM:Object-XML-Mapping),然后转化为JSON数据(XML-2-JSON)。

JsonWithPaddingInterceptor.aroundWriteTo(WriterInterceptorContext) line: 91

WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorContext) line: 188

ConfigurableMoxyJsonProvider(MOXyJsonProvider).**writeTo**(Object, Class<?>, Type, Annotation[], MediaType, MultivaluedMap<string,object style="margin: 0px; padding: 0px;">, OutputStream) line: 782

  • object Book (id=7076)
  • type Class (com.example.domain.Book) (id=568)
  • genericType Class (com.example.domain.Book) (id=568)
  • annotations Annotation3
  • mediaType AcceptableMediaType (id=7120)
  • httpHeaders StringKeyIgnoreCaseMultivaluedMap (id=7121)
  • entityStream CommittingOutputStream (id=7124)

开始从对象转化为JSON:

JAXBMarshaller.marshal(Object, OutputStream) line: 395

  • object Book (id=7076)
  • outputStream CommittingOutputStream (id=7124)

XMLMarshaller(XMLMarshaller<abstract_session,context,descriptor,media_type,namespace_prefix_mapper,object_builder style="margin: 0px; padding: 0px;">).marshal(Object, OutputStream, ABSTRACT_SESSION, DESCRIPTOR) line: 852

XMLMarshaller(XMLMarshaller<abstract_session,context,descriptor,media_type,namespace_prefix_mapper,object_builder style="margin: 0px; padding: 0px;">).marshal(Object, Writer, ABSTRACT_SESSION, DESCRIPTOR) line: 1031

  • object Book (id=7305)
  • writer OutputStreamWriter (id=7310)
    -> BufferedWriter (id=7333)

XMLMarshaller(XMLMarshaller<abstract_session,context,descriptor,media_type,namespace_prefix_mapper,object_builder style="margin: 0px; padding: 0px;">).marshal(Object, MarshalRecord, ABSTRACT_SESSION, DESCRIPTOR, boolean) line: 583

  • object Book (id=7305)
  • marshalRecord JSONWriterRecord (id=7342)
  • session DatabaseSessionImpl (id=7351)
  • descriptor XMLDescriptor (id=7353)
  • isXMLRoot false

几经辗转,写入对象变成了MarshalRecord。

JSONWriterRecord.startDocument(String, String) line: 171

TreeObjectBuilder.marshalAttributes(MarshalRecord, Object, CoreAbstractSession) line: 122

XPathObjectBuilder.marshalAttributes(MarshalRecord, Object, CoreAbstractSession) line: 552

这里是可以想见的流程...

ServerRuntime$Responder.processResponse(ContainerResponse) line: 362

最后是将response返回并释放。流程到此结束。

 

本文收录在我的新书《Java Restful Web Service使用指南》中

https://code.csdn.net/delva/jax-rs2-guide/tree/master/sample/2/5simple-service-webapp-spring-jpa-jquery/request_flow.md

 

请留意写作动态

https://code.csdn.net/delva/jax-rs2-guide/

 

0
3
分享到:
评论
3 楼 aa51513 2016-06-23  
中文乱码式硬伤
2 楼 marshan 2013-09-10  
每一个JSR标准都有一个以上的实现,但其中只有一个是官方的实现。对于JavaEE7的JAX-RS2标准,Jersey是其官方实现。其实不止Spring的MVC模块实现了该标准,还有Apache的CXF,JBoss的RestEasy。
但不管使用哪种实现,需要从REST原理学起,明白了标准的定义,才可以写好REST式的API。
我正在写这方面的书,如有哪些疑问,欢迎交流啊!
1 楼 cywhoyi 2013-09-09  
好奇的不是剖析它的原理,疑问的是为何想到使用Jersey?貌似现阶段国内很少使用Jersey,restful基本上都是采纳springMVC,有时候我也在怀疑以后用Jersey!

相关推荐

    spring4.x 集成 jersey2.x 实现对外提供接口服务

    在本文中,我们将深入探讨如何将Spring 4.x框架与Jersey 2.x结合,以构建一个能够对外提供RESTful接口服务的系统。这个过程包括了配置、组件整合以及实际的API开发。以下是对整个集成过程的详细说明。 首先,让我们...

    Jersey-2.x-User-Guide-Demos:《 Jersey 2.x用户指南》的演示《 Jersey 2.x用户指南》

    4. **异步处理**:Jersey 2.x 支持异步请求处理,通过 `@Suspended` 注解和 `AsyncResponse` 接口,可以处理长时间运行的任务而不会阻塞服务器线程。 5. **客户端 API**:除了提供服务器端的支持,Jersey 2.x 还...

    spring4.x + jersey2.x +restful

    Jersey 2.x版本提供了许多新特性,如更强大的过滤器和拦截器、支持Guice和CDI集成、以及对Java 8的兼容性等。通过集成Spring,Jersey可以利用Spring的IoC容器,实现服务组件的管理和依赖注入。 **三、RESTful API...

    jersey2.x+hibernate4+spring3+jquery

    在IT领域,构建Web应用程序是常见的任务,而`jersey2.x+hibernate4+spring3+jquery`是一个经典的组合,用于构建高效、灵活且功能丰富的后端服务与前端交互。下面将详细阐述这个组合中的各个技术及其整合方式。 **...

    Jersey 2.x All 以及教程文档

    基于 Jersey 的 REST 实战。在做 Java RESTful 相关的项目,发现网上中文的资料比较少,而且 Jersey 的更新比较快,利用业余时间写了本书,图文并茂,用大量...有关 Jersey 详细信息,可以参阅《Jersey 2.x 用户指南》

    Jersey-2.x-User-Guide:Jersey 2.x User Guide《Jersey 2.x 用户指南》 ,中文翻译

    Jersey-2.x-User-Guide Chinese translation of .There is also a GitBook version of the book: . Let's ! 《Jersey 2.x 用户指南》 ,中文翻译。 最近在做Java RESTful 相关的项目,借此机会学习了一把Jersey,...

    rest jersey 所必须的jar包

    8. **hk2-api.jar, hk2-utils.jar, aopalliance-repackaged.jar, hk2-locator.jar, hk2-runlevel.jar**:这些是HK2依赖注入框架的组件,Jersey 2.x使用HK2来管理服务的生命周期和依赖关系。 在初学开发Jersey时,...

    jersey jar.zip

    【jersey jar.zip】是一个包含Jersey框架的压缩文件,Jersey是Java世界中用于构建RESTful Web服务的开源框架。这个zip包很显然是为了方便开发者快速地在项目中引入和运行RESTful服务。REST(Representational State ...

    jersey实现简单的rest接口

    &lt;groupId&gt;org.glassfish.jersey.containers &lt;artifactId&gt;jersey-container-servlet-core &lt;version&gt;YOUR_JERSEY_VERSION ``` 接下来,我们创建一个简单的REST服务。定义一个Java类,用`@Path`注解标记它的根URL...

    使用Jersey 2.x的RESTFul Web服务(第一部分)

    **使用Jersey 2.x构建RESTful Web服务(第一部分)** RESTful Web服务是一种遵循Representational State Transfer(表述性状态转移)架构风格的网络应用设计模式,它以简洁、可扩展的方式提供服务。在Java世界中,...

    jersey1.18 jar包

    10. 持续学习:Jersey不断更新和发展,了解新版本特性,如Jersey 2.x引入了更多现代化的特性,如支持Java 8,更好的性能和灵活性,以及对Java EE 7的兼容性。 总之,"jersey1.18 jar包"是开发RESTful服务的重要工具...

    android-jersey-client:Jersey 1.x客户端库的即插即用Android版本

    基于v1.17.1的即插即用Android版本的Jersey 1.x客户端库。 当前端口基于上的v1.17.1 要在Android Maven项目中使用它,您需要将以下存储库和依赖项添加到项目pom.xml中。 仓库: &lt;repositories&gt; ... ...

    com.sun.jersey.jersey-core-1.4.0.jar

    com.sun.jersey.jersey-core-1.4.0.jar jar包下载,jar包下载

    jersey-media-jaxb-2.22.2-API文档-中文版.zip

    Maven坐标:org.glassfish.jersey.media:jersey-media-jaxb:2.22.2; 标签:glassfish、jersey、media、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容...

    jersey1.19.1所有相关jar

    Jersey是Java中的一款流行的RESTful Web服务框架,它基于JAX-RS(Java API for RESTful Web ...对于新项目,考虑使用Jersey 2.x或者其他REST框架如Spring Boot的REST支持,可以获得更好的社区支持和更先进的特性。

    org.glassfish.jersey.media,jersey-media-multipart,2.24.1

    org.glassfish.jersey.media:jersey-media-multipart:2.24.1 Jersey 上传文件以及下载文件所需的依赖库,maven下载比较慢,我手动下载下来了。放到你的libs目录

    jersey所有jar包下载

    9. **版本兼容性**:Jersey 的不同版本可能与不同的 JAX-RS 规范版本对应,比如 1.x 版本对应 JAX-RS 1.1,2.x 版本对应 JAX-RS 2.0 及以上。因此,在选择版本时要考虑所使用环境的兼容性。 总的来说,Jersey 提供...

    Jersey 1.2 jar包 文档 打包下载

    Jersey是Java世界中著名的...在实际项目中,开发者可能会选择更新的版本,如Jersey 2.x,以获取更多的特性和支持。然而,了解Jersey 1.2可以帮助我们更好地理解RESTful服务的实现原理,为后续的学习和开发奠定基础。

    phonecat-parent:使用 JAX RS - Jersey 2.x 和 Spring 4.x 的 PhoneCat App API

    总结起来,"phonecat-parent:使用 JAX RS - Jersey 2.x 和 Spring 4.x 的 PhoneCat App API"项目是一个全面展示Java RESTful服务开发的实例,涵盖了从服务设计、实现到测试的整个流程,涉及的技术包括JAX-RS、Jersey...

Global site tag (gtag.js) - Google Analytics