【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

人人网移动开发架构

  • 2011-03-14
  • 本文字数:7789 字

    阅读完需:约 26 分钟

前言

说起手机操作平台的发展先要说移动终端的发展,因为平台的发展离不开移动终端,近十年移动终端发展和未来移动终端趋势大体可分为以下四个个阶段:

第一个阶段:功能终端。满足用户基本通信需求,如发短信、打电话,附加些贪食蛇、推箱子小游戏。

第二个阶段:智能化的终端。可扩展第三方应用,实现上网浏览等互联网基础功能,以诺基亚 S60 手机为代表的。

第三个阶段:互联网和平台化的终端。手机和互联网更加紧密,浏览器、流媒体更加强大,互联网应用和手机系统特性结合的更加紧密;手机成为了一个平台,用户可以通过下载第三方应用来 DIY 这款终端,如偏好音乐,可以下载音乐类型的应用。代表为 iPhone、Android 和 Windows Phone 7。

第四个阶段(未来趋势):物联网化的智能终端。此阶段的特点是现实生活和网络通过传感设备结合的更加紧密。

目前我们处于第三个阶段,对用户而言,由于收入不同、兴趣爱好不同、需求偏好的不同以及手机私人属性和随身性的特点,产生了不同的用户体验;对各个厂商而言,由于目标市场的定位不同、商业利益的不同、技术背景不同,造就了不同的手机操作系统。最终形成了手机操作平台多元化的局面。

目前主流手机操作平台可分为:Symbian、Android、iPhone OS 、MTK、Windows mobile、Wp7 六种。下面分别简述下这六个平台的情况。

Symbian:昔日王者,虽然眼下受到了 android 和 iPhone 的强势狙击,被其瓜分了部分市场,但是价格低,易用性强,应用程序多,加上诺基亚的品牌、渠道等优势,在短期内智能机霸主地位很难撼动。中期来看市场中心下移走中低端智能机路线,长期来看,有可能被 WP7 取代。如果它不革自己的命,那么很可能被别人革命。

Android:势如破竹,据国外媒体报道 Android 在去年第四季度已超过 Symbian 成为全球最大智能手机平台,结束了在 Symbian 在智能机领域长达 10 年的统治地位。作为后来者,Android 借鉴了 iPhone 的操作体验,但是由于 Android 完全开源,对于手机厂商和运营商来讲,很容易定制成自己特色和服务的手机,加上 Android 强大的互联网功能,因而获得二者的青睐。完全开源是把双刃剑,由于各厂商分别定义了各自的产品,这种不标准和不统一会给第三方软件适配带来门槛,会导致在单个某型号的移动终端 Android 应用偏少,所以 Android 有可能成为智能手机中的山寨机。

iPhone OS:神话缔造者,从热销的程度我们可以看出 iPhone 4 创造的奇迹。超炫的 UI 设计,良好的交互操作,海量的应用,牢牢占领高端市场。从短期来看,iPhone 4 突出的优势会让它再火一段时间。但是由于是自有系统,市场占有量取决于苹果手机终端用户认可情况,所以长期看,主要取决于苹果手机发展和竞争对手的变化。

Windows mobile:廉颇老矣,尚能饭否?无论从 UI 视觉效果,还是从易用性,还是第三方应用,Windows mobile 都完败 Iphone 和 Android。壮士暮年,该退隐江湖了。

MTK:山寨大王, MTK 是一个封闭的环境,不支持可扩展的应用,同时原功能也不完善,总之是个半成品。需要中间厂商来完善。相比较来讲,第三方程序少,易用性一般。山寨机的价格和功能形成的性价比优势,占据低端市场。

WP7:救世主,作为微软和诺基亚的救命稻草是值得期待的,笔者曾经体验过 WP7,采用卷轴式 UI 设计风格,使 UI 体验别具一格。系统和互联网应用的紧密结合,加上诺基亚和微软的强力支持。这个操作系统是值得期待的,有望在智能机领域形成 WP7、Android、iPhone 三足鼎立的局面。

上述六大平台分别对应不同的体验和功能实现。对产品设计人员和开发人员而言,它们通常会参照移动终端的 UI 设计规范。因为移动终端系统本身定义了一些常用的控件和响应方式。产品保持与终端系统的一致,不但可以降低开发成本,而且易于用户学习和使用。面对诸多平台,尤其是各个平台功能特点不尽相同,操作方式不同,屏幕大小不同,而每个主流平台又有相当规模的用户群,拥有众多不同的 UI 规范,这对于全平台的产品而言,无疑是具有灾难性的。

本文就人人网移动开发中不同终端平台的差异和架构统一问题,以及相关服务器架构进行探讨。

移动终端之江山一统

历史历历在目

人人网 www.renren.com(原名: 校内网),从08年下半年开始手机软件的研发,当时国内一二线的互联网公司也已经开始了移动互联网的布局,但已发布并可供参考的产品并不多,尤其是 SNS 本身也还是一个新的互联业务,让我们的用户可以在手机上方便地访问 SNS,这可一下把我们难住了。为了可以快速推出第一个版本试水,我们先是选择 JavaME 平台来开发第一个人人的手机客户端。

人人网的主要业务包括新鲜事,个人主页(状态,日志,相册,留言),好友,站内信,聊天,游戏等等,这些业务都互相关联与衬托,并围绕好友关系(Social Graph),如果要把这些业务都搬到手机,短时间内根本无法完成,因为客户端类的软件与浏览器的网页在展现与交互上有非常大的差异,手机的屏幕大小限制也给设计带来了很大的困难,无疑是雪上加霜。当时我们挑选了用户常用的几个业务,新鲜事,个人主页(状态,日志,相册,留言),好友,站内信,按主站顶部导航的排版方式,设计了一多标签的导航界面,每个标签一个业务,页面跳转同主站,如下图:

图 1

看上去这个设计非常简约明到几乎完美,代码也非常好实现,大家激情澎湃,斗志昂扬准备迎接移动互联网的又一个奇迹,也许你和我以及我们的产品经理一样,低估了这一切,人人网的业务可不像聊天软件那样单纯,当我们的工程师各自完成自己的分配到的业务,并开始处理不同业务之间界面的跳转时,不详的预感笼罩了整个团队,当时的轻率导致了严重危机,大家知道,在我们通过浏览器访问网页,页面中超链接可以让你随意跳转到任何一个页面,且这些页面并不一定是同一个业务的相关页面,如我从个人主页也可以直接跳转到好友(跨标签),而且通过浏览器的后退按钮可以返回前面的页面,客户端类软件可不能做成这样的自由,我们应该怎么处理不同业务界面的跳转呢?当时大家理解的跳转,根本没有考虑到不同业务之间后退的问题,而且浏览器的页面跳转,浏览器本身是不用知道下个界面是哪个业务,而客户端必须知道,否则根本无法处理事件交互。技术慌了,产品经理也慌了,眼看承诺的交付时间一天天临近,大家还是没有想出一个非常好的办法,多次尝试失败,有的方案,页面的跳转连我们自己都晕过去了,最后我们的第一个版本的 JavaME 客户端1.0以失败告终。

首战不利,大家心里都不是滋味,虽然通过后几个月的努力,最后我们决定将1.2版本的客户端以 beta 版本的形式发布,并公开提供了下载,除了拍照上传这个功能让我们值得高兴一下之外,其它功能也许只是让我们感觉能用而已。JavaME 的失利让我们从自负中清醒,骄兵必败。经过一段时间的讨论与分析,大家一致认为,我们需要一个手机浏览器,人人的业务不论在 PC 端还是手机端,最理想的展现方式还是浏览器,于是我们开始手机浏览器研发道路,我们花了3-4 个月的时间,开发出了我们第一个基于 JavaME 的浏览器引擎,代号:Across(为什么起这个名,后面说)。浏览器引擎架构参考 Webkit,如下图:

图 2 Across**** 浏览器结构图

上图中蓝色部分是我们引擎的实现部分,红色的 JS,CSS 及 Plug-in 是未来的计划,从技术角度看来,这个架构看上去非常的美,模块功能划分清晰且扩展性强,我们只要重写 Render Engine 可以把一个普通的页面渲染成我们想要的任何效果,遗憾的是最终我们还是没有把浏览器这个解决方案应用到正式发布的人人客户端版本,原因很简单,它还不是很完善。我们预先做了大量的测试用例,在完成开发以后,我们按测试用例逐条进行了测试,最终结论虽然在性能和 xhtml 标签支持上达到了我们的预期,但稳定性和包体积却并没有达到理想的状态:运行时内存消耗在 xhtml 页面大小的 8-10 倍左右,如一个 30K 的 xhtml 页面完成解析,渲染必须保证有 300K 左右的空闲内存,如果渲染多个页面或频繁渲染新的页面,就很容易出现崩溃(后来我们发现代码中还有存在一些内存泄漏的地方);另外,打包以后 200k 的体积对于 JavaME 手机来说已经大了。09 年上半年,Android 发布了 1.5 的 SDK,iPhone 入华的消息也是传得到处都是,显然,在这样的行业形势下,公司管理层已经对我们在 JavaME 上做浏览器引擎的计划失去兴趣,我们的工程师被重新安排了新的任务,Across 没有见到用户就成了历史,浏览器没有救得了我们。

痛苦中反思

09 年上半年是我们最痛苦的一段时间,折腾了大半个年头,结果我们没有发布一个值得骄傲的产品,市场却快速变化着,iPhone,Android 带着闪耀的光芒进入了大家的视野,我们也不得不做出调整,开始分兵投入 iPhone 及 Android 的阵营。我们开始反省前面的失败,我们似乎走了两个极端,第一次在考虑产品及技术的架构时过于的简单草率,以致后期面临强大的心理压力,第二次却是一个典型的过度设计案例,虽然从技术角度看这是一个非常有挑战且非常有意思的项目,当时我们的设想是先完成 JavaME 平台的浏览器,然后移植 Symbian 等其它平台,统一架构。但是移动互联网市场近几年的急速变化,不论从人力和时间上都不允许我们再把浏览器项目继续下去。

为什么我们要统一架构?

人人网的业务种类非常多,而且 PC 端都基于浏览器网页的模式,不论内容还是排版都经常需要优化变更,如果我们通过纯客户端的形式把全部现有业务迁移到到手机端,那么,当我们完成第5个业务的迁移时,可以前两个业务主站已经发生了变更,或者客户端刚刚上线之前的某个业务已经需要兼容运行了,在这种情况下,要么我们能快速迭代客户端版本,赶上主站的业务的迭代速度,要么我们使用浏览器或类似浏览器的模式,所有业务放在服务器做,这就是我们为什么考虑开发 Across,名字意在横跨所有手机终端平台。

真的可以统一架构吗?

可以,浏览器本身就是一个非常优秀的跨平台解决方案,但这个方案的前期投入非常大,且项目执行风险过高,人人网的业务大都是基本动态网页实现,使用了大量的 AJAX 及 Flash 技术,最终我们放弃了浏览器方案,我们要的统一架构肯定不是这个。

山穷水尽,柳暗花明

放弃了浏览器的方案,我们可谓山穷水尽,难道还有第三个方案?Facebook 的 iPhone 应用给了我们很大灵感,看图:

图3

从产品的角度看,这个图显示的布局与我们第一次尝试的设计没什么区别,深入一点我们会发现,这个设计与之前的设计最大区别在于页面跳转,每个标签都有独立的一个视图栈,理论上无限大,通过当前栈顶视图可以打开新的视图后自动压栈保存,当前视图如果要后退默认退回视图栈里保存的上一个视图的内容。那如果是标签1的页面需要跳转到标签2对应的页面怎么办呢,是否自动切标签?答案是不切,标签只是用于业务导航,且有独立的视图栈,视图栈中的页面可以与业务无关,打个很好理解的比方:当我们在使用 Chrome 的浏览器时,我们同时在多个标签分别打开多个不同网站或页面,也可以打开同样的网站或页面,每个标签都有一个独立的后退的记录,这种设计非常有规律,用户容易理解不容易晕,现在页面跳转及后退的问题很好的解决了。不论 JavaME,还是 iPhone 或者 Android 的客户端,我们都使用了同样的设计。

数风流人物,还看今朝

当我们客户端都使用了这种标签 + 视图栈的方案以后,我们的各平台在设计上基本达到了统一,并在现有设计上快速迭代演进。大家可能想了,在代码层统一这才叫本事,也许你没错,但是我们不会轻意再做这样高风险的尝试,如今手机平台的差异相当的大,就从主流平台的开发语言看就够你折腾了,JavaME 及 Android 是使用的 Java , iPhone 使用的是 Objective-C,Symbian 是纯 C++, 现在诺基亚与微软联姻 WP7,可 WP7 将不再支持 C/C++ 的开发,主推 C# + Silverlight,好吧,我们只能再观察一下了。

在接下来的一到两年,移动互联网将以前所未有的速度发展,大部分互联网公司都开始了或已经推出了较成熟的移动终端的解决方案,创业公司也会层出不穷,推出各种优秀的移动终端应用:移动支付,LBS,基本通讯簿的即时通信,手机音乐,手机视频,手机阅读等等,iPad 点燃平板电脑的硝烟,平板的设计再次给了我们很大的挑战,数风流人物,还看今朝。

高可靠性和可扩展的服务

现在移动互联网拼的都是服务,客户端良好的用户体验背后,都有强大的服务器技术支撑,人人网也不外如是。

业务层次模型

人人网采用 JavaEE 技术作为主要的业务解决方案,基本按照通用的 JavaEE 模型进行架构设计,如下图:

图 4 人人网业务层次模型

  • WEB 层基于 REST 风格和 MVC 设计模式,为用户提供基于 WEB 的访问接口 人人网采用的是自己开发的 WEB 框架 Rose,该框架基于 Spring Framework,类似 RoR 框架,增强了对 Controller 编码部分的默认约定和 REST 风格 URL 的支持,该项目前已开源,下载地址为 http://code.google.com/p/paoding-rose/

  • 业务层封装业务逻辑,为 WEB 层提供业务接口,操作数据访问层提供的数据。 人人网开发了自己的 SOA 框架 XOA 以支持业务层抽象,该框架结合 Rose 框架,以 REST 风格对业务进行分类、消息格式封装和路由,如以下 URL:

    xoa://blog.xoa.renren.com/photo/{user-id}/{photo-id}

    该 URL 代表某用户的某个照片,操作 GET/PUT/POST/DELETE 分别对应对应照片资源的读、修改、新增、删除。即通过资源 + 操作的方式对外提供 Service。

    XOA 支持远程调用,并可以通过简单添加服务器的方式进行横向扩展。该框架目前准备开源,敬请关注。

  • 数据访问层提供对数据库访问的封装 人人网使用 Java 语言开发了自己的 Object-Relation Mapping 框架 JADE(Java Database Engine),并支持数据库的水平横向切分。该框架和 Rose 框架一体开源,下载地址相同。

  • 数据持久层数据的持久存储,主要采用 MySQL 数据库,并且开发了自己的海量存储系统 Nuclear。 Rose、Jade、XOA 作为集成度很高的一整套解决方案,在人人网大量采用,大大降低了开发成本,并在框架级解决了服务于企业解决方案的 JavaEE 技术在互联网领域的适用性。

可扩展的高性能系统

人人网每天都要承受亿级 PV 海量用户的并发压力,和其它大型互联网站点类似,服务器架构方面做了很多工作。

高性能数据存储系统

在数据存储方面,人人网做了以下工作:

  • 和其它互联网大型站点相同,MySQL 数据库做水平拆分以支持横向扩展
  • 人人网作为国内第一大 SNS 网站,欲存海量 UGC 数据,必有海量存储系统。Nuclear 存储系统在高性能、高可靠、可扩展的海量数据存储需求下横空出世。

Nuclear 本身的数据存储基于 Key-Value 形式,底层可以使用 MySQL/Memory, Cassandra, TC, Redis 等存储引擎,提供弱结构化的查询功能。

  1. 高扩展性 一个 Nuclear 集群支持 1 到 n(n<264) 个节点 (Node) 的规模
  2. 高可靠性 单个节点的 crash 永远对系统的运行造成影响,不存在单点风险。系统永远可写入。
  3. 高性能 在 4 个节点、一般服务器配置情况下有测试数据表明单节点访问可达 15862 req/s, 平均单次请求耗时仅 5ms。

本文不欲详细介绍 Nuclear, 有兴趣的读者请参考我们的技术站点

可扩展的高性能业务服务系统

人人网的业务层是支持分布式、可横向扩展的。

  • 人人网主要使用 JavaEE 架构进行业务开发,其中 Spring 提供的 IoC 和 AOP 功能分别起到了业务对象装配和横向关注点分离的良好抽象。XOA 框架基于 Spring 和 netty,使用 google 的 spdy 协议作为网络传输协议,除享受到 Spring 红利之外,也提供了基于 Java NIO 的网络高性能服务器环境。单个 XOA 服务是无状态的,具有幂等性,XOA 客户端使用 Java NIO、通过 Keep alive 保持对各个后台服务器的 TCP 长连接,可实时监测后台服务器的健康状况,并把用户请求负载分散到各个后台服务器上,在单个节点失效的情况下不影响服务,如图 5 所示:

    图 5 XOA**** 负载均衡

  • 很多关键性的业务对性能要求特别高,也需要借助很多 Linux 操作系统的特性,这时 Java 的优化已经不能满足需求,需要使用 C++ 语言进行开发。人人网采用 ICE 框架,进行这部分业务的开发,它解决了 Java、C++ 等多种语言开发的框架和通讯问题。人人网目前使用 ICE 进行开发的业务层称之为中间层,主要解决类似搜索、用户好友关系计算等性能要求苛刻的底层关键性业务问题。其运维模式和 XOA 类似。 和其它大型网站一样,业务层使用 Memcached 作为业务层的分布式数据缓存,且根据业务将缓存集群划分为多个池,集中进行管理,如图 6 所示:

    图 6 Memcached Pool

  • 在 WEB 层,使用目前性能最高的 Servlet 容器产品 Resin 作为 HTTP Server,使用自行开发的 Java WEB MVC 框架 Rose 对用户请求请求分发。负载均衡方面使用了 F5 或者 nginx。为了减少 Session 复制同步的开销,每台 WEB Server 都禁用 Servlet Session, 即每台服务器都是无状态的,单个 Web Server 失效后,不会发生用户状态丢失的问题。用户状态的跟踪由中间层统一处理。

对移动终端的支持

服务器对移动终端的支持主要是通过 HTTP 协议提供 json 数据接口实现的,服务器基本采用了人人网共同的架构:

  • HTTP WEB 层做了更多的 MVC 抽象,除了提供基于 html 的 Page View 之外,还生成只提供 json 或者其他数据格式的 Feed View。
  • 服务器通过 gzip 压缩减少流量,节省用户资费。
  • 客户端构建 REST 风格的 HTTP 请求,WEB 服务器下发数据完成远程调用。

3G 的 API 层直接面向移动终端,提供基于 HTTP 和其他 Socket 协议的服务器访问接口,并在业务层抽象出 3G 部门自己的公共平台,如图 4 所示:

图 7 3G API**** 架构

除此之外,针对移动终端的特点和中国特色的移动互联网环境,做了一些特殊的工作:

  • 低端机型运算能力和内存资源都有限,API 平台做了相应优化
    • 复杂的运算服务器完成,减少移动终端负载。如图片的缩放、裁剪运算、图片质量就是服务器进行的。
    • 客户端和服务器进行的数据输入输出尽量减小,这样可以节省内存存储。在表示相同数据的情况下,尽量采用数据量小且易于解析的格式。API 平台使用了 JSON,没有使用 XML
  • 为了减少用户资费,传输流量进行了控制
    • nginx 开启 gzip 压缩,减少网络传输流量。
    • 中国移动的 cmwap 网关会自动对服务器输出的 gzip 流进行解压缩,从而使 nginx 的 zip 压缩失去了意义。这种情况下,api 服务器对输出进行 gzip 压缩后,作为普通二进制流进行响应输出。
    • 除了纯文本的 json 之外,api 服务器也支持基于 google protocol buffers 格式的输出,从而提供更紧凑的格式输出。
  • 提高客户端访问速度
    • Api 平台支持基于逻辑时序的批处理操作,将多个 api 的网络接口调用合并为一个,减少多次 tcp 握手造成的巨大时间损耗,提高客户端每个 UI 界面的响应和显示速度。

作者简介

闫志东,人人网 3G 事业部高级技术经理,资深工程师,人人网技术委员会委员,目前负责人人网 3G 部门服务器架构方面的工作,他在基于 C++、Java 的服务器技术和架构方面拥有多年经验。个人非常喜欢阅读计算机技术、科幻、历史类书籍。

闻华强,人人网 3G 事业部高级技术经理,资深工程师,是人人网 3G 部门客户端技术负责人,他有长达七年的移动终端开发和管理经验。阳光男孩,热爱体育运动,对《明朝那些事儿》爱不释手,是忠实的明矾。

马小东,人人网 3G 事业部产品经理,在移动互联网业界浸淫七年,对很多产品大趋势的把握和细节设计有非常独到的看法。爱手机、爱生活、爱人人。


感谢侯伯薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011-03-14 00:0016969

评论

发布
暂无评论
发现更多内容

Storage API简介和存储限制与逐出策略

程序那些事

大前端 浏览器 web tech web storage storage api

vivo 基于原生 RabbitMQ 的高可用架构实践

vivo互联网技术

高可用 RabbitMQ 中间件

技术实操丨HBase 2.X版本的元数据修复及一种数据迁移方式

华为云开发者联盟

数据 数据迁移 原数据

十九、深入Python匿名函数

刘润森

Python

视频面试跟传统面试的区别及优点

anyRTC开发者

ios 音视频 WebRTC RTC 安卓

在网上被MG坑审过却一直延迟无法取出到账怎么解决 (LGF微7998)

Geek_db0f9e

spring-boot-route(二十一)quartz实现动态定时任务

Java旅途

Java Spring Boot quartz

最火的HTAP数据库 京东智联云新一代分布式数据库TiDB架构揭秘

京东科技开发者

数据库 #TiDB

解锁华为云AI如何助力无人车飞驰“新姿势”,大赛冠军有话说

华为云开发者联盟

AI 无人驾驶

MySQL-技术专题-MySQL的主从同步

洛神灬殇

让核显大展拳脚:Intel Iris Xe显卡

E科讯

LeetCode题解:98. 验证二叉搜索树,递归中序遍历完成后再判断,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

Java程序员想要进阶,想了解Java服务器的深层高阶知识,Netty绝对是一个必须要过的门槛。

Java架构之路

Java 程序员 架构 编程语言 随笔杂谈

美腻了!Java资深架构师带你深度学习字节跳动的亿级流量+高并发

Java架构追梦

Java 学习 架构 面试 微服务

1分钟带你入门React Context

Leo

大前端 React useContext Context

身为程序员你们经历过大厂面试吗?本文为大家解决大厂必问的MySQL调优问题

Java架构师迁哥

独家!阿里技术人限产的MySQL高级笔记及面试宝典,简直开挂

996小迁

Java MySQL 架构 面试 技术宅

1分钟带你入门Redux、React-Redux

Leo

大前端 React Redux React-Redux

原来AI也可以如此简单!教你从0到1开发开源知识问答机器人

华为云开发者联盟

开源 AI 机器人

1分钟带你入门 Redux 中间件

Leo

大前端 中间件 Redux Redux中间件

独家!阿里技术人限产的MySQL高级笔记及面试宝典,学完简直开挂

Java架构追梦

Java MySQL 数据库 架构 面试

【活动预告】2020中国系统架构师大会:即构受邀分享实时音视频服务架构实践

ZEGO即构

架构师 高并发系统设计 技术分享

WebSocket硬核入门:200行代码,教你徒手撸一个WebSocket服务器

JackJiang

html5 网络编程 websocket 即时通讯

【运维思考】运维对象快速扩展,监控如何精准实时的覆盖?

嘉为蓝鲸

PaaS 运维自动化 监控管理平台 监控系统 监控告警

杂谈:一文了解工业4.0

soolaugust

工业互联网 工业4.0

连续一个月每天加班到凌晨三点,终于把Java程序员必知必会的计算机底层操作系统知识和网络知识整理出来了,已整理成文档!

Java架构之路

Java 程序员 架构 编程语言 操作系统

膜拜!阿里技术总监纯手打的《MySQL笔记》内部资料限时分享

Java架构师迁哥

iOS 性能优化实践:头条抖音如何实现 OOM 崩溃率下降50%+

iOSer

性能优化 OOM ios开发 头条抖音 OOM崩溃

BIGDATA+AI Meetup 2020第二季·上海站开启报名!

Apache Flink

大数据 AI

一套完整的后台管理系统(附源码),非常实用!

程序员生活志

管理系统

基于注解的参数校验器Hibernate Validator

HelloLittleRain

Java springboot 参数校验 Hibernate-Validator

人人网移动开发架构_架构_闫志东_InfoQ精选文章