济南Java培训
达内济南山大路中心

17156168575

热门课程

面向Java 开发人员的 Node.js

  • 时间:2016-07-20
  • 发布:济南java培训
  • 来源:济南java培训

在本文中,我将为您介绍服务器端脚本的革命,那就是 Node。首先我们从整体结构上总揽全局,看看是什么让 Node 与众不同,然后会演示如何快速构建一个使用 MongoDB 持久化数据的可扩展性 Web 应用程序。您将会亲身体验 Node 是多么有趣,并且看到用它来组建一个有效的 Web 应用程序有多快。

Node 的事件驱动并发

Node 是建立在 Google 的 V8 JavaScript 引擎基础上的一个可扩展、事件驱动 I/O 环境。Google V8 实际上在执行之前就将 JavaScript 编译到本机机器代码中,从而达到快速的运行时性能,实际上这与 JavaScript 关系不大。Node 本身能够让您快速构建速度极快、高度并发的网络应用程序。

事件驱动 I/O 对 Java 开发人员来说可能有些陌生,但并非是全新的概念。与 Java 平台中使用的多线程编程模型不同,Node 处理并发的方法是单线程加上事件循环。Node 结构可以确保不会不堵塞和异步 I/O 传输。那些通常会引起堵塞的调用如等待数据库查询结果等在 Node 中不会发生。Node 应用程序不是等待代价高昂的 I/O 活动来完成操作,而是会发出一个回调(roll back)。当资源返回后,会异步调用关联的回调。

为什么选择 Node.js?

Java 平台处理并发的方式帮助确立了其在企业开发方面的领导地位,这很难发生改变。诸如 Netty(以及 Gretty;参阅 参考资料)的框架和诸如 NIO 和java.util.concurrent 的核心库,使得 JVM 成为处理并发的首选。Node 的特别之处就在于它是专门为应对并发编程而设计的现代开发环境。Node 的事件驱动编程方式意味着,您无需添加额外的库来处理并发性,这对关注多核硬件的开发人员来说是个好消息。并发性在 Node 程序中照样工作。如果在 Java 平台上运行之前的场景,我可能会选择复杂且耗时的方法,从传统的线程到 Java NIO 中较新的库,甚至是改善和更新的java.util.concurrent 包。尽管 Java 的并发很强大,但却难以理解,还要用它来编码!相比而言,Node 的回调机制是嵌在语言内部的;您不需要添加诸如 synchronized 这样额外的结构使它工作。Node 的并发模型极其简单,让广大的开发人员都能够接受。

Node 的 JavaScript 语法也为您减少敲键的次数,节省大量时间。只需少量代码,您就能构建快速的、可扩展的 Web 应用程序,并且它能处理大量的并发连接。当然您也可以在 Java 平台上实现,但将会需要更多代码行和一大堆库和结构。如果您担心对新的编程环境不熟悉,那么大可不必:如果已经了解一些 JavaScript,那么 Node 很容易学习,这一点我可以向您保证。

回页首开始使用 Node

如前所述,Node 很容易上手,而且有很多好的在线教程可以为您提供帮助。在本文中(以及我的 Java 开发 2.0:面向 Java 开发人员的 JavaScript 中),我重点关注的是帮助 Java 开发人员理解 Node 的优势。我不会从标准的 “Hello, world” Web 服务器应用程序讲起,我会直接讲解一个有实际意义的应用程序:将它想象成在 Node 上构建的 Foursquare 网站。

视频演示:开始使用 Node.js

想要换种方式学习这个方便的框架?观看此 视频演示,这也是由 Andrew Glover 演示的,通过它来学习关于 Node.js 的更多内容,并了解它能为您做些什么。(阅读视频演示的文字版。)安装 Node 需要您遵循特定平台的说明;如果您使用的是 UNIX 一类的平台,如 OSX,那么我推荐您使用 Node Version Manager 或 NVM,它能处理安装正确版本 Node 的细节信息。无论哪种情况,请现在就 下载并安装 Node。

我们还使用了第三方库来构建此应用程序,因此您可能还想 安装 NPM,它是 Node 的包管理器。NPM 允许您指定项目的版本依赖关系,这样就可以下载并包含在您的构建路径中。NPM 在很多方面很像 Java 平台的 Maven,或者是 Ruby 的 Bundler。

回页首Node Express

Node 在 Web 开发人员心目中占据一席之地,一是因为它对并发的处理能力,二是它是按 Web 开发的需求构建的。最流行的一个第三方 Node 工具是轻量级 Web 开发框架 Express,我们将会用它来开发应用程序(参阅 参考资料 以了解关于 Express 的更多内容)。

Express 有很多特性,包括复杂路由、动态模板视图(参见 Node 框架 du jour: Jade)和内容协商。Express 是非常轻量级的,没有内嵌的 ORM 或类似东西来加重其负担。在这一方面,Express 无法与 Rails、Grails 或其他有完整堆栈的 Web 框架相比。

安装并使用 Express 的一个简单方法是通过 NPM package.json 文件将其声明为依赖关系,如清单 1 所示。该文件与 Maven 的 pom.xml 或 Bundler 的 Gemfile 类似,但它是 JSON 格式的。

清单 1. 清单 1.NPM 的 package.json 文件

{

"name":"magnus-server",

"version":"0.0.1",

"dependencies":{

"express":"2.4.6"

}

}

在 清单 1 中,我赋予 Node 项目一个名称 (magnus-server) 和一个版本号 (0.0.1)。我还将 Express 2.4.6 版本声明为一个依赖关系。NPM 的一个好处就是它会获取 Express 所有的传递依赖关系,迅速加载 Express 所需的其他所有第三方 Node 库。

通过 package.json 定义项目依赖关系之后,就可以通过在命令行输入 npm install 来安装所需的包。您会看到 NPM 安装 Express 和依赖关系,如 connect、mime 等等。

编写网络应用程序

我们通过创建一个 JavaScript 文件来编写示例应用程序;我将其命名为 web.js,但实际上可以随便起一个名字。在您最喜欢的编辑器或 IDE 中打开此文件;例如,您可以使用 Eclipse JavaScript 插件 JSDT(参阅 参考资料)。

在此文件中,添加清单 2 中的代码:

清单 2. Magnus Server:第一步

var express = require('express');

var app = express.createServer(express.logger());

app.put('/', function(req, res) {

res.contentType('json');

res.send(JSON.stringify({ status:"success" }));

});

var port = process.env.PORT || 3000;

app.listen(port, function() {

console.log("Listening on " + port);

});

这一小段代码发挥了很大的作用,因此我从头讲起。首先,如果想要在 Node 中使用第三方库,就要用到 require 短语;在 清单 2 中,我们需要 Express 框架,并通过 express 变量获得其句柄。下一步,我们通过 createServer 调用创建一个应用程序实例,它会创建一个 HTTP 服务器。

然后我们通过 app.put 定义一个端点。在本例中,我们定义一个 HTTP PUT 作为在应用程序根部 (/) 监听的 HTTP 方法。put 调用有两个参数:路由和调用路由时相应的回调。第二个参数是在运行时端点 / 被启动时的调用函数。记住,此回调就是 Node 所谓的事件驱动或事件 I/O,即异步调用回调函数。终端可以同时处理大量请求而不必手动创建线程。

作为端点定义的一部分,我们创建处理 / 的 PUT 逻辑。为了简单起见,我们将响应类型设置为 JSON,然后发送一个简单的 JSON 文档:({"status":"success"})。请注意这里的 stringify 方法恰到好处,它会接收哈希表然后将其转换成 JSON 格式。

JavaScript 和 JSON

JSON 和 JavaScript 是同胞兄弟,这种关系延续到了 Node 中。在 Node 应用程序中解析 JSON 无需特别的库或结构;您可以使用与对象图类似的逻辑调用。简而言之,Node 对待 JSON 就像自有的类型一样,这就使得编写基于 JSON 的 Web 应用程序变得非常简单。下一步,创建用来表示应用程序所监听的端口的变量;可以通过获取 PORT 环境变量或直接设置为 3000 来完成。最后,通过调用 listen 方法来启动此应用程序。我们再次传入一个回调函数,它将会在应用程序启动并运行至将消息打印到控制台时被调用(本例中,是standard out)。

试一下!

这个完美的应用程序会对所有 PUT 作出响应,因此只要在命令行输入 node web.js 即可运行。如果您想要进一步测试该应用程序,我建议您下载 WizTools.org 的 RESTClient。有了 RESTClient,您就可以通过对 http://localhost:3000 执行 HTTP PUT 以快速测出 Magnus Server 是否工作正常。如果正常,您会看到表示执行成功的 JSON 响应。(参阅 参考资料 了解更多有关安装和使用 RESTClient 的信息。)

回页首在 Express 中处理 JSON

JavaScript 和 JSON 紧密关联,这使得在 Express 中管理 JSON 变得非常简单。在这一节,我们将在 清单 2 的主应用程序中添加一些代码,从而能获取传入的 JSON 文档并将其打印到 standard out。然后,我们将所有内容持久化为 MongoDB 实例。

传入的文档与清单 3 类似(请注意,简单起见,我省略了位置信息):

清单 3. Freddie Fingers 的免费午餐!

{

"deal_description":"free food at Freddie Fingers",

"all_tags":"free,burgers,fries"

}

清单 4 添加了解析传入文档的功能:

清单 4. 用 Express 解析 JSON

app.use(express.bodyParser());

app.put('/', function(req, res) {

var deal = req.body.deal_description;

var tags = req.body.all_tags;

console.log("deal is :" + deal + " and tags are " + tags);

res.contentType('json');

res.send(JSON.stringify({ status:"success" }));

});

请注意,清单 4 中包含了一行代码指引 Express 使用 bodyParser。这会让我们能轻松地(我是说轻松地)获取传入的 JSON 文档的属性。

put 回调函数中的代码是用来获取传入文档的 deal_description 和 all_tags 属性值。请注意,我们获得请求文档的每个元素时是多么轻松:在本例中,req.body.deal_description 获取 deal_description 的值。

测试一下!

你也可以对此实现进行测试。关闭 magnus-server 实例并重启,然后使用一个 HTTP PUT 将一个 JSON 文档提交到 Express 应用程序中。首先,您会看到一个成功响应。其次,Express 会把您提交的值发送到 standard out。通过使用我的 Freddie Fingers 文档,我获取了输出结果。

deal is : free food at Freddie Fingers and tags are free, burgers, fries.

回页首Node 的持久性

我们已经拥有了一个工作正常的应用程序,它能接收和解析 JSON 文档,并返回响应。现在要做的就是增加一些持久性逻辑。由于我偏爱 MongoDB(参见 参考资料),因此我选择通过 MongoDB 实例持久化数据。为了让处理过程更简单一些,我们将会用到第三方库 Mongolian DeadBeef,我们将用它来存储传入 JSON 文档的值。

Mongolian DeadBeef 是众多的用于 Node 的 MongoDB 库中的一个。我之所以选择它是因为我觉得它名字很有趣,还因为它对本机 MongoDB 驱动的监控功能让我非常满意。

现在,您已经知道,使用 Mongolian DeadBeef 的第一步是升级 package.json 文件,如清单 5 所示:

清单 5. 添加 JSON 解析

{

"name":"magnus-server",

"version":"0.0.1",

"dependencies":{

"express":"2.4.6",

"mongolian":"0.1.12"

}

}

由于我们将会使用 MongoDB 数据存储,因此需要通过运行 npm install 来更新项目的硬件依赖关系。为了提高 Mongolian DeadBeef MongoDB 驱动的性能,我们还需要安装本机 C++ bson 解析器,NPM 能指导我们完成这一过程。

在开始使用 Mongolian DeadBeef 之前,在现有的实现中再添加一个 require,然后连接到所需的 MongoDB 实例上(如清单 6 所示)。在本示例中,我们将连接到由 MongoHQ 托管的实例上,它是 MongoDB 的云供应者。

清单 6. 将 Mongolian DeadBeef 添加到 magnus-server

var mongolian = require("mongolian");

var db = new mongolian("mongo://a_username:a_password@flume.mongohq.com:23034/magnus");

在 PUT 回调函数中,我们持久化来自传入的 JSON 文档的值,如清单 7 所示:

清单 7. 添加 Mongolian insert 逻辑

app.put('/', function(req, res) {

var deal = req.body.deal_description;

var tags = req.body.all_tags;

db.collection("deals").insert({

deal: deal,

deal_tags: tags.split(",")

})

res.contentType('json');

res.send(JSON.stringify({ status:"success" }));

});

仔细看,您会发现 insert 语句和 MongoDB shell 中的 insert 一样。这不是巧合,MongoDB 的 shell 也使用了 JavaScript!因此,我们能够轻松地持久化拥有两个字段的文档:deal 和 deal_tags。请注意,我们通过对 tags 字符串使用 split 方法将 deal_tags 设置为数组。

可以测试吗?(当然可以!)

如果您想要测试一下(有谁不想呢?),那么重启实例,再发送一个 JSON 文档,然后再检查 MongoDB 中的 deals 集合。您应该会看到一个与您发送的 JSON 文档几乎一模一样的文档。

清单 8. 添加 Mongolian insert 逻辑

{

deal:"free food at Freddie Fingers",

deal_tags:["free", "burgers", "fries"],

_id:"4e73ff3a41258b7423000001"

上一篇:Java 理论与实践之非阻塞算法简介
下一篇:80后励志小伙参加达内java培训,从一线工人变身白领薪资翻3倍

达内携手惠普 英特尔,共同打造引领数字化职业教育解决方案

第四届“达内发现杯”大学生互联网软件设计大赛圆满落幕

795万高校毕业生创历史新高,2017届毕业生就业近况几何?

写给Python程序员:如何利用Rust取代C/C ++?

选择城市和中心
贵州省

广西省

海南省

台湾