`

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!

相关推荐

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

    java Jersey Rest

    ### Java Jersey REST Web Services开发详解 #### 一、名词解释 **1. REST (Representational State Transfer)** - **定义**: REST是一种软件架构风格,主要用于设计网络应用的API。其核心理念是“资源”...

    jersey

    6. **MVC 风格的支持**:Jersey 2.x 引入了 MVC 风格的编程模型,允许开发者使用类似于 Spring MVC 的方式编写 REST 服务。 7. **模块化**:Jersey 可以与其他 JAX-RS 实现互换,因为它遵循标准。此外,可以通过...

    upickle_2.10-0.1.1.zip

    【标题】"upickle_2.10-0.1.1...通过这些知识点,开发者不仅可以学习如何在Scala中处理JSON数据,还可以掌握如何在DropWizard框架下构建微服务,以及如何参与到开源项目中,提升个人的编程技能和对软件开发流程的理解。

    基于A*算法的往返式全覆盖路径规划改进及其Matlab实现

    内容概要:本文详细介绍了如何利用A*算法改进传统的往返式路径规划,解决扫地机器人在复杂环境中容易卡住的问题。首先构建了一个可视化的栅格地图用于模拟环境,然后引入了优先级运动规则,使机器人能够有规律地进行往返清扫。当遇到死角时,通过A*算法计算最佳逃生路径,确保机器人能够顺利脱困并继续完成清扫任务。实验结果显示,改进后的算法显著提高了清洁覆盖率,降低了路径重复率。此外,还讨论了一些潜在的优化方向,如动态调整启发函数权重、断点续传以及能耗模型等。 适合人群:对路径规划算法感兴趣的科研人员、自动化专业学生、扫地机器人开发者。 使用场景及目标:适用于需要高覆盖率和低重复率的室内清洁任务,旨在提高扫地机器人的工作效率和智能化水平。 其他说明:文中提供了详细的Matlab代码实现,并附带了仿真测试结果,有助于读者理解和复现该算法。

    爬取喜马拉雅听书(1).py

    爬取喜马拉雅听书(1)

    安卓向上传递数据学习笔记总结

    安卓向上传递数据学习笔记总结

    tigervnc-selinux-1.11.0-9.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统tigervnc-selinux-1.11.0-9.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf tigervnc-selinux-1.11.0-9.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    户外储能电源双向逆变器板生产资料及技术规格详解

    内容概要:本文详细介绍了户外储能电源双向逆变器板的技术资料及其特点。涵盖原理文件、PCB文件、源代码、电感与变压器规格参数等,适用于2KW(最大3KW)的户外储能电源。文中强调了双向软开关DC-DC设计、两颗M0+ 32位MCU的分工、SPWM调制方式、H桥IGBT的应用、详细的电气参数和技术特性。此外,还包括了SPWM信号生成代码示例、硬件设计细节、生产注意事项等。 适合人群:从事户外储能电源开发的技术人员、电子工程师、产品经理等。 使用场景及目标:帮助开发者快速掌握双向逆变器板的设计和生产要点,缩短产品研发周期,提高产品质量和可靠性。具体应用场景包括但不限于户外应急电源、便携式储能设备等。 其他说明:本文提供了丰富的技术细节和实践经验,如双向软开关DC-DC设计、SPWM调制、IGBT驱动、EMC整改记录等,有助于解决实际开发中的难题。同时,附带的实际案例展示了该方案的成功应用,进一步证明了其可行性和优越性。

    电能质量分析:间谐波分析.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    【计算机科学领域】美国计算机学会(ACM):组织架构、使命愿景、核心价值及活动项目介绍

    内容概要:美国计算机学会(ACM)是一个成立于1947年的国际性计算机专业组织,致力于推动计算机科学的发展,提供教育、资源和专业发展机会。ACM的使命是促进计算机科学和信息技术领域的进步,愿景是成为全球计算机专业人士的首选组织。其核心价值包括卓越、诚信、包容性、合作和创新。ACM定期举办学术会议,如SIGGRAPH和图灵奖颁奖典礼,出版高质量的学术期刊和会议论文集,涵盖人工智能、软件工程、网络安全等领域。此外,ACM还提供在线课程、研讨会、认证项目等教育资源,以及职业规划、网络机会和领导力培训等职业发展服务。ACM图灵奖被誉为“计算机界的诺贝尔奖”,每年颁发给对计算机科学和技术做出重大贡献的个人。; 适合人群:计算机科学领域的专业人士、教育工作者、工程师和学生。; 使用场景及目标:①了解计算机科学领域的最新研究成果和发展趋势;②获取高质量的教育资源和职业发展机会;③参与计算机科学领域的学术交流和合作。; 其他说明:ACM作为一个全球性的组织,在教育、研究和行业实践中发挥着重要作用,推动了技术创新和社会进步。

    最新版logstash-8.17.4-windows-x86-64.zip

    logstash-8.17.4-windows-x86_64.zip

    一个基于Springboot使用Aspect实现一个切面,以记录日志为例

    springboot 一个基于Springboot使用Aspect实现一个切面,以记录日志为例

    音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    基于Python Django MySQL的个性化图书推荐系统:协同过滤算法及远程部署实现

    内容概要:本文详细介绍了如何使用Python、Django和MySQL构建一个完整的个性化图书推荐系统。系统从前端界面设计、后端逻辑实现到数据库设计,涵盖了用户管理、图书管理、评分系统等功能模块。重点讲解了基于用户和项目的协同过滤算法实现,以及在用户评分数据不足时的标签推荐备份方案。此外,还包括了系统部署、测试和优化的具体步骤,如云服务器部署、性能测试、数据库优化等。 适合人群:具备一定Python和Web开发基础的研发人员,尤其是对推荐系统感兴趣的技术爱好者。 使用场景及目标:适用于希望深入了解图书推荐系统的工作原理和实现细节的技术人员。目标是帮助读者掌握从零开始搭建一个完整的个性化推荐系统的方法,包括前后端开发、算法实现和系统部署。 其他说明:文中提供了大量代码示例和实战经验,如数据库设计、爬虫实现、权限管理等,有助于读者更好地理解和应用相关技术。

    Ai和python学习资料

    Ai和python学习资料

    文本摘要.py

    文本摘要

    冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    Java开发MybatisPlus框架详解:增强Mybatis功能实现高效CRUD操作与代码生成

    内容概要:本文详细介绍了MyBatis Plus(MP),它是MyBatis的增强工具,旨在简化CRUD操作、提高开发效率。其主要功能包括内置分页插件、简化CRUD操作以及代码生成器。使用时只需引入相应依赖,自定义Mapper接口继承BaseMapper泛型接口,并通过实体类反射获取数据库表信息。文章还介绍了常用注解如@TableName、@TableId、@TableField、@TableLogic和@Version,配置项如全局配置、类型别名和Mapper文件路径,以及核心功能如批量插入、分页查询、条件构造器(Wrapper)等。此外,扩展功能涵盖逻辑删除、枚举处理器和JSON处理器,插件功能则包括分页插件的配置和使用。 适合人群:具备一定Java开发经验,尤其是熟悉MyBatis框架的开发者,特别是那些希望提高开发效率、减少重复代码的工作1-3年研发人员。 使用场景及目标:①简化数据库操作,提高开发效率;②快速生成代码,减少手动编写SQL语句的工作量;③实现分页查询、逻辑删除、枚举和JSON字段处理等高级功能,提升应用的灵活性和可维护性。 其他说明:本文不仅提供了MyBatis Plus的功能介绍和使用方法,还深入探讨了条件构造器(Wrapper)的使用技巧,帮助开发者更好地理解和掌握这一强大的工具。在实际开发中,合理利用这些功能可以显著提高开发效率和代码质量。建议在学习过程中结合具体项目实践,逐步掌握各个功能的应用场景和最佳实践。

    电路仿真:射频电路仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

Global site tag (gtag.js) - Google Analytics