服务化体用术之"用" —— JAX-RS IN ACTION

前言

在 Java 的 Web 世界中,构建Web应用最为常见的 dispatcher 框架,老一点的 Struts 系列,现在最为流行的 SpringMVC。它们起初的目标都是构建基于模板的 web 应用程序,也就是作为一名当时的程序员,前后端都得会。

而随着分布式系统 和 互联网的发展,前后端分离、后端服务化的趋势越来越明朗,SpringMVC 加入了诸如 @RestController 这样概念性的 annotation 以 restful 风格的 webservice call 来语义上支持前后分离 和 后端的服务化。前端程序员不强调必须会后端,后端程序员也不强调必须要会前端,JAX-RS 不论用来做 Web 与前端程序员的分离, 或者后端一系列的服务都是一个非常好的选择。

从 51cto 来的图来表述前后端分离:

从百度查来的后端分布式服务图:

1、对应后端概念

相信资历比较老一些的研发,或多或少得接触过 SOA(Service Oriented Architecture)、ESB(Enterprise Service Bus)、RPC(Remote Procedure Call), 还有最近的微服务 这些概念即是为构建复杂的分布式系统而生,为后端服务化提供一套套解决方案的思路。

ESB 企业资源总线例子图(百度来的与作者理解一致的图,作者很懒):

2、概念的 Implementations

这些思路的出现,也有着对应的 java 框架进化着 ——— 从遥远过去的程序员制定规则到 SOAP 标准的出现到 Sun 建立的 Restful webservice 标准 — JAX-RS, 再到后来基于 Netty 的一系列 RPC 框架, 诞生了非常非常多优秀的 Java 框架,如下面举一些我的程序职业中见过得一些例子。

WebService的SOAP标准系列: Apache Axis2、Codehaus XFire、Apache CXF

Rest 的 WebService 的 JAX-RS 系列: RestEasy、Jersey、CXF

基于 Netty 的 RPC 系列: Finagle、JProtobuf(我们点融内部服务项目在使用这个RPC框架)、Thrift、apache avro

它们让我们从使用菜刀的冷兵器战场到使用AK47的热兵器时代。

3、派别模式的优点和区别

在我的 java 世界中有两个派别:第一派即 j2ee 系列,走的是标准化道路,先有标准的定义,再由具体厂商去实现,再慢慢地进化标准; 另一派走得比较敏捷一些(Spring 系列), 反设计模式的特性,使得这一派如鱼得水;它们共同构成了 java web 的世界,模式不同但又相互交融。

j2ee、spring 类似的对比图:

讲了这么多,我们进入我将要介绍的正题——JAX-RS, 它属于 Restful 系列的标准、是 j2ee 系列中的产物之一。

那么何为标准呢?标准就像你我写程序时定义的 interface,我拿着接口使用其中一个实现,即可实现系统的交互; 标准,也如同攻城射击狮画攻城图纸使用了神器-UML (统一建模语言), 画出来的东西,程序员就能够直接懂里面发生了什么, 大大减少非标准路子造成的程序员之间的沟通问题; 是标准 也就提供了通过编程序使程序理解程序、自动生成代码的可能性。

JAX-RS 是一种标准也即拥有了这些优点,看了我的后面的代码,你会发现后端程序员可以这样构建 Restful 的 Webservice 服务 和 客户端。

下面的代码中我将介绍一些 JAX-RS 标准能为我们带来的好处,如:

自动生成可与服务器交互的客户端

在客户端、服务端埋点:

—— Track可能的性能问题

—— 传递一些作为上游服务器拥有的session类参数给无状态的服务端

—— 其他, 如 配合配置服务器做 服务注册与发现; 由调用方传入 transactionId保证事务最终一致; 使用 token(如 jwt) 来获得 api 的访问权限 etc。

4、Talk is cheap, show me the code.

为了避免篇幅过于冗长,代码中仅提供 “四”中明确提出的 3个好处的实现。

1)我们既然是 In action, 我不解释太多标准细节的东西,读者可以自行通过附件1提供的链接,去查询标准相关的细节,下面是两张 JAX-RS 的 Lifecycle(具体请参见附件 spec 链接)的图片,读者可以先尝试理解一下图片 以帮助理解程序。

Server-side :

Client-side:

2)将附录2中的源代码下载下来,用 intellij 或 eclipse 以 gradle 项目形式导入. 该项目的 JAX-RS 标准由 cxf 实现,与 Springboot 进行集成,在将项目导入后找到 类 Application, 右键 debug run,即可将该 springboot 的服务器端启动。

3)服务端启动后,http 服务即被放在了 http://localhost:8080, 可访问 http://localhost:8080/ws 测试 cxf servlet dispatcher 是否启动成功。此时找到 类 ClientMainDemo,这个类既是我们生成的客户端 它是业务逻辑、性能监控、传递一些 session 信息给 stateless 服务的使用 main 方法的测试。我们在 “2” 中的服务启动好之后,直接 debug 执行 ClientMainDemo 中的 main 方法:

具体代码详解我们下一步再讲(其实我不想讲解代码,代码即是文档,还烦请各位有兴趣的同学下载代码来看,代码并不复杂)我们可以看到如下的日志:

case a.

第一个 request 在服务端可以看到日志:

在客户端看到日志:

我们可以看到,服务器发现了一个 request,并且记录了它被 call 了一次(我在代码中加的日志),与此同时 在客户端我们看到该 request 发起和结束的日志, 可以统计到 request 的状态、耗时等信息, 在客户端的track埋点功能 done。

case b.

是 DEMO 中的第三个 request, 我们将一个 ThreadLocal 中的变量设置好, 并使用 jaxrs 的 provider 进行拦截并将该值读取出来放进 http request 的 header。

我们可以在客户端看到日志:

服务端看到日志:

4)执行步骤“3”之后,我们发现我们需要的三个功能都已经实现了, 我们再来具体看一看代码是怎么做的(具体的框架搭建请参考源码):

1、自动生成可与服务器交互的客户端(该客户端需要 publish 成 jar 包到 repo 中,给集成方使用) CXF 框架提供了一个叫做 JAXRSClientFactory 的类, 可以根据 endpoint + 接口 + jaxrs providers 的方式来生成客户端接口, 详细代码参见JaxrsExampleFacade

2、埋点 track 客户端执行性能(服务端我没做), 读者可以自己做我自定义了一个类 叫做 UUIDHeaderClientRequestFilter,该类实现了 jaxrs 标准中 client 端的两个 filter 接口, 并且我将其放进了 client 的生命周期,即可用于生成每个 request 的 uuid 并且将其性能 track 起来,代码如下:

3、传递一些作为上游服务器拥有的 session 类参数给无状态的服务端与 UUIDHeaderClientRequestFilter 一样,  实现一个叫做 OperatorHeaderClientRequestFilter 的 jaxrs provider (多个 provider 之后请读者注意控制它们的 Priority),该 Filter 会从 ThreadLocal 中读取变量值,放进 requestheader,具体代码如下:

与此同时在服务器端也实现一个叫做 OperatorFilter 的类, 作为 jaxrs 的 provider 实现 ContainerRequestFilter 和 ContainerResponseFilter, 将 http header 中的值读出来并放到 ThreadLocal 中, 在 request 结束时清空 threadlocal,详细代码如下:

希望这篇文章在您的服务化之路上有一定思路上的帮助。

附录:

jax-rs spec下载地址:https://jcp.org/aboutJava/communityprocess/final/jsr339/index.html

本文源码地址:https://github.com/Agileaq/jax-rs-example.git

Uniauth的读服务提供给了点融网各个集成系统,其服务提供的war包 使用了这一套解决方案并且代码已经开源,源码: https://github.com/dianrong/UniAuth

cxf jaxrs文档: http://cxf.apache.org/docs/jax-rs.html

有任何疑问, 都欢迎直接与我联系并交流经验: 286999915@qq.com ,  微信号  Arc_Qian

本文作者:钱晟龙 Arc_Qian(点融黑帮),现任点融网架构组产品研发工程师,主要任务是思考并尝试解决各类点融网迈出第一公里之后遇到的现实问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 我是个喜欢记录生活点滴的人,在无锡绿点电子厂打工的这几年,我都会记录一些人和事,今天跟大家分享一个我遇到的事情,也...
    看一树春秋阅读 243评论 0 0
  • A1: 3个月以前,上班期间部门经理来到我们的办公室,说我们与航材部门昨晚交接了一个轮胎,对方收到的轮胎不完整,有...
    陈醋君阅读 122评论 1 0
  • 我们活在这个世上,从一降生就注定了这一生的坎坷与挫折。 没有人的一生是一帆风顺的。我们的人生就像心电图似的有高就有...
    呆丫阅读 978评论 3 2