提供一个 EC2 实例来托管 Java Web 应用程序将非常简单。在这一期 Java 开发 2.0 中,我们将快速构建一个利用 Groovy、Spring 和 Hibernate(通过 Grails 框架)的 Web 应用程序并将其部署到一个 EC2 实例。
正如您从 “Java 开发 2.0:您也可以租用 EC2” 中了解到的一样,Amazon 的 Elastic Compute Cloud (EC2) 是一个用于托管(Linux®、OpenSolaris 甚至 Windows®)虚拟机的通用基础设施服务,您可以在这些虚拟机上运行任何程序。假如您创建或借用了一个虚拟机,也可以将其称为 Amazon Machine Image (AMI) 或实例,那么您可以运行任何 Java 应用程序 — 包括使用 Hibernate 和 Spring 的 Web 应用程序,正如我将在本文所展示的一样。
围绕 Amazon 的 Web 服务产品的社区在过去几年中一度非常活跃,并且您可以从一组完整的公共虚拟机分类中选择一种虚拟机来使用。Linux 提供了许多不同版本的虚拟机,因此可以想象得到虚拟机分类附带了各种软件配置和相关工具。对于本文来讲,我将选择符合以下条件的 AMI:
已经安装了某种 Java 版本(最好是一个较新的版本) 具有一个 servlet 容器,例如 Tomcat 具有一个免费可用的数据库,例如 MySQL
寻找 AMI
通过浏览 Amazon 的扩展分类,您不仅可以寻找符合需求的 AMI,某些 AMI 提供商还在 Web 上提供了它们独有的实例,包括免费的和商用的。例如,Java Web Apps in a Box 就非常适合本文的 Java Web 开发项目。我在 Java Web Apps in a Box 站点中找到了启动该实例所需的所有重要 AMI ID(我将在本文后面演示这一过程)。
我还有另外一个选择,那就是使用一种 “空白” 虚拟机,然后在其中安装这些组件。但是您需要花些时间寻找大量的配置。事实上,在大多数情况下,EC2 供应中最困难的部分在于寻找符合您的要求的特定虚拟机。一旦找到这样的虚拟机后,那么您将开始从中获得乐趣!我真的找到一个符合我的要求的虚拟机,我将展示如何使用它。这非常简单,如果您已经安装了我在前一篇文章中提及的 Eclipse AWS 插件的话,那么就更简单了。
Eclipse AWS 插件允许您搜索、启动和终止实例;并且,假如您已经正确配置了一个键对(插件可以很好地处理),那么您可以通过一个特定映像的终端窗口执行 ssh,以进行进一步的配置。
然而,就像上一次一样,当我开始展示 EC2 的细节时,在启动公共 AMI 之前,最好构建一个快速 Java 应用程序。通过使用 Grails 框架,应用程序将利用 Spring 和 Hibernate(并因此使用一个底层的持久化存储)。
速度是关键
在使用借来的基础设施的过程中,Java 开发 2.0 的一个重要方面就是利用开源技术以自上而下的方式构建应用程序。通过使用开源工具、框架甚至是解决方案,公司可以迅速地组装应用程序,因为他们自身不需要编写大量代码。当谈到能够使开发变得迅速并且更加简单的开源解决方案时,首先想到的两个框架就是 Spring 和 Hibernate。
实际上,世界上的所有 Java 组织都使用 Spring 框架构建应用程序。尽管它主要以一种反转控制(IoC)框架而著称,但是它确实成为了 Java 开发的主力。(Spring 是一种面向方面的编程 [AOP] 框架、一种 OSGi 容器、一个 Web 框架等)。Hibernate 亦不逊色,它是 Java 对象-关系映射(ORM)领域中的重量级框架。Java Data Objects (JDO)(我在本系列第一期中已经使用 Google App Engine 进行了演示)的采用率在任何方面都不及 Hibernate。因此,当我思考当前以及未来的 Java 开发时,很可能会想到结合使用 Spring 和 Hibernate。(这并不表示您需要同时使用这两者来完成某项特定工作,只是说明在大部分情况下,这两个框架基本上可以满足您的全部需求)。
与此同时,Groovy 是一种可以大大简化 Java 开发的开发平台。Groovy 实际上就是简化了语法的 Java 语言。它允许您将重心放在快速构建解决方案上,而不是周而复始地编写大量 Java 代码来解决相同的问题。(Groovy 在这方面并非独树一帜。运行在 JVM 上的许多其他语言都可以处理相同的问题)。对于我来说,Groovy 仅仅是我的工具箱中的另一个 JAR 文件。
因此,当我考虑快速构建应用程序时,我想到了 Groovy、Spring 和 Hibernate。对于 Web 应用程序,有一种特殊的框架可以将这三者完美地结合在一起,该框架就是 Grails。Grails 构建在 Spring 之上并基于 Groovy。并且 Grails Object Relational Mapping (GORM) — Grails ORM 实现 — 在内部使用 Hibernate。
本文并不会重点介绍 Grails。(如果您希望精通 Grails 的话,我建议您阅读 Scott Davis 的 精通 Grails 系列)。也就是说,使用 Grails 构建简单 Web 应用程序将超乎寻常地简单。
使用 Grails!
Grails 的入门非常简单。跟随本文的步骤,您很快就会得到一个利用数据库的基本 Web 应用程序(通过 Spring 和 Hibernate)。首先,下载 Grails,将其解压缩,然后设置一个指向安装目录的 GRAILS_HOME 环境变量来对环境进行配置。随后将 GRAILS_HOME/bin 添加到您的路径。同样,确保您得到了一个 JAVA_HOME 环境变量。
现在打开一个控制台窗口或 shell(根据您的操作系统)并在命令提示中输入以下内容:
grails create-app mytri
这将毫无意外地创建一个名为 mytri 的 Grails Web 应用程序,这与我在本系列早期文章中展示如何使用 Google App Engine 进行构建时使用的 triathlon-tracking 应用程序的通用主题相一致。
接下来,将目录切换到新创建的 Web 应用程序(cd mytri/)并输入:
grails create-domain-class Triathlon
您应当会发现 Grails 输出了一些代码行,其结尾类似如下内容:
Created DomainClass for TriathlonCreated Tests for Triathlon
现在,将目录切换到 grails-app/domain。在该目录中,您将发现一个文件被命名为 Triathlon.groovy。在任意一种编辑器中打开这个文件。正如本系列早期文章一样,我不会花太多时间关注这类内容。也就是说,从现在起,我将进行非常扼要的介绍(您总是可以在稍后进行补充);我将忽略铁人三项赛(triathlon)的各种关系,而是关注它的一些属性:
日期 类型(短跑、半程铁人三项赛等) 名称 位置
因此,将清单 1 中的代码添加到您的 Triathlon.groovy 文件:
清单 1. 表示一个 triathlon 的样例域对象
class Triathlon { static constraints = { classification(inList:["Sprint", "Olympic", "1/2 Iron Man", "Iron Man"] ) } String name String location Date eventDate String classification}
注意对象的 constraints 部分是如何指定 classification 只能为四种类型的其中之一的。保存并关闭文件。
接下来,返回到项目的主目录(mytri)并输入以下内容:
grails generate-all Triathlon
该命令将创建模型-视图-控制器(MVC)的视图和控制器部分。Triathlon 对象就是模型。
现在可以深呼吸一下了,因为您已经完成了工作。您刚刚创建了一个简单的 Web 应用程序,它可以在数据库中创建、更新、移除和读取 triathlon。很令人振奋,不是吗?要运行此应用程序,输入以下命令:
grails run-app
打开浏览器并访问 http://localhost:8080/mytri。您将看到在我的域对象中,Grails 生成了一些支持 CRUD(创建、读取、更新、删除)的通用接口。
例如,当 mytri 应用程序加载时(参见图 1),应当会看到一个指向 TriathlonController 对象的链接,该对象是在您运行 generate-all 命令时由 Grails 生成的:
图 1. 默认 Grails 应用程序主页
单击 TriathlonController 链接将显示底层数据存储为空。但是如果随后单击 New Triathlon 链接,您将看到一个用于创建 triathlons 的表单,如图 2 所示:
图 2. 用于创建 triathlon 的表单
使用一些数据填充该表单,然后单击 Create 链接,您将被带回到可用 triathlons 列表。您新创建的对象现在已经显示在列表中,如图 3 所示:
图 3. 成功的 triathlon 创建
在内部,Grails 使用了一个名为 HSQL 的内存数据库;然而,您接下来将导出 Grails 正在使用的模式并做好准备,以便在 MySQL 内部创建一个数据库表。
将 Grails 配置为与数据库交互(而不是与 HSQL 交互)将非常简单。访问 mytri/grails-app/conf 目录并使用您喜欢的编辑器打开 DataSource.groovy 文件。在文件的 dataSource 部分,添加如下代码:
dialect=org.hibernate.dialect.MySQLDialect.class
这行代码将告诉 Grails 使用 Hibernate 的 MySQL 方言(dialect);特别是,您希望 Grails 生成一个有效的 MySQL Data Definition Language (DDL) 文件。因此,接下来,在您的控制台中,确保您位于项目的主目录并输入如下内容:
grails schema-export
这一处理将生成一个复制的 sql.ddl 文件,其中包含您用来在 MySQL 内创建相应表的语句(您将在稍后执行这一步骤)。最后,从 DataSource.groovy 文件中删除 dialect 行 — 稍后将把它放回到一个不同的位置。
供应 Amazon 实例
好了,您现在已经完成了许多工作,但是尚未触及 EC2。但是,这是一件好事。EC2 以及类似服务的魅力在于它们非常简单,并且可以被立刻触发。相应地,打开 Eclipse(安装 AWS 插件并配置它,如果还没有这样做的话 — 如有必要,参见上一个月的文章获得指导)并打开 Amazon EC2 Management 透视图。从该透视图中,单击 EC2 AMIs 视图。您应当会看到一个非常奇怪的列表,其中包含 ID 和清单,并且视图的右上角有一个文本框,如图 4 所示:
图 4. AMI 清单
在不显眼的文本框中,输入 ami-aa5abac3。这是 Java Web Apps in a Box 提供的方便的 AMI 的 ID。图 5 显示了结果:
图 5. 我需要的 AMI
可以从图 5 中看到,ami-aa5abac3 AMI 已经被找到,并且它的清单包含有 tomcat 和 mysql 几个词 — 不算坏,我们取得了一些进展。接下来,选择 AMI,右键单击,然后选择 launch 选项。您将看到一个新的对话框显示出来,其中允许您配置 AMI 的启动。在启动 AMI 时,应当选择一对键和一个安全组(就像在 “Java 开发 2.0:您也可以租用 EC2” 中所做的一样),如图 6 所示:
图 6. 配置 AMI 启动选项
单击 Finish 按钮,正如您猜想的一样,这将在 Internet 中的某个位置启动 AMI。您可以在 Eclipse AWS EC2 Instances 视图中看到,如图 7 所示,您的实例的启动处于待定状态:
图 7. Eclipse AWS EC2 Instances 视图
AMI 的状态将由启动变为运行。这可能需要一些时间,因此耐心些。一旦实例进入运行状态,您将注意到 Eclipse AWS EC2 Instances 视图显示出针对您的 AMI 的公共 DNS。这可以帮助您稍后导航到您的 Web 应用程序。
您需要一个终端会话来进一步配置 MySQL。选择实例,右键单击,然后选择 Open Shell 选项。根据本地机器的操作系统,您可能需要寻找一个支持 SSH 的 shell。(如果您使用的是 Windows 操作系统,那么可以使用 Putty;)。
配置 MySQL 和 Grails
在从 Eclipse 内部打开的、指向新启动的 AMI 的 shell 中,通过以下命令登录到 MySQL:
mysql -u root --password=root
随后为您的 Grails 实例创建一个新用户:
mysql> CREATE USER 'grails'@'localhost' IDENTIFIED BY 'groovy';
然后向此用户授予数据库权限:
mysql> GRANT ALL ON *.* to 'grails'@'localhost';
接下来,创建一个数据库(或模式,根据您看待数据库中事物的方式):
mysql> create database mytri;
您必须随后开始使用新创建的数据库,以创建一些表:
mysql> use mytri;
最后,执行 sql.ddl 文件中的最后一行代码(不要出现任何中断):
mysql> create table triathlon ( id bigint not null auto_increment, version bigint not null, classification varchar(12) not null, event_date datetime not null, location varchar(255) not null, name varchar(255) not null, primary key (id));
现在您的 MySQL 数据库已经可以投入使用了。剩下的工作就是配置 Grails 以使用它。
配置 Grails 以使用 MySQL
下载 MySQL JDBC 驱动程序并将其放到 mytri/lib 目录中。接下来,打开 DataSource.groovy 文件并更新 production 部分,如清单 2 所示:
清单 2. 将 MySQL 驱动器和 dialect 配置添加到 DataSource.groovy
production { dataSource { driverClassName = "com.mysql.jdbc.Driver" username = "grails" password = "groovy" dialect=org.hibernate.dialect.MySQLDialect.class url = "jdbc:mysql://localhost/mytri" }}
这一修改将指向在同一台机器(本地主机)上运行的底层 MySQL 数据库上的 Grails 生产实例。当然,本地主机实例是一个在某处运行的 AMI。
通过 Tomcat 管理接口部署 Grails 应用程序
本地测试
仅仅是出于节省时间的考虑,我将跳过对 Grails 的配置了 MySQL 的实例进行本地测试的内容。也就是说,我假设您并未对 MySQL 进行本地安装,因此我将利用 EC2 映像上的一个现有 MySQL 实例来保持简单性。让我再讲清楚一些:如果您计划在生产中使用 MySQL,那么在云中启动它之前,您应该进行本地安装并在本地测试应用程序是否正常工作。
Grails 应用程序 — 就如同任何 Java Web 应用程序一样 — 的部署方式和 WAR 文件没什么两样。相应地,回到您的计算机的 shell 中(即您用来处理 Grails 的 shell,而不是指向 EC2 实例的 shell),输入下面的内容:
grails -Dgrails.env=prod war mytri.war
这将创建一个名为 mytri.war 的文件。现在,需要使用 Tomcat 的管理接口在新触发的 AMI 上加载应用程序。或者,您也可以将 mytri.war scp 到目标 AMI。选择权在您手中;在这里,我倾向于使用 Tomcat 的接口,因为 Tomcat 已经在运行中,并且我不必寻找它在底层文件系统中的路径。
配置 Tomcat 的管理接口
在使用 Tomcat 的管理接口之前,您必须在 EC2 映像上恰当地启用它,因为 AMI 已经被默认配置为禁用此接口(出于安全考虑):
返回到指向 AMI 接口的 shell 会话,并查找位于 /usr/local/tomcat-6.0.20/conf 目录的 tomcat-users.xml 文件。 打开该文件并添加一个名为 manager 的新角色。 创建一个新用户(或使用现有用户)并确保该用户具有 manager 角色。 重启 Tomcat。您可以通过 Eclipse 控制台重启您的实例,或是返回到 /usr/local/tomcat-6.0.20/bin 目录并先后运行停止脚本和启动脚本 — 由您决定。
返回到 Eclipse EC2 Instances 视图,右键单击实例,然后选择 Copy Public DNS Name。然后将名称粘帖到浏览器的位置框。您应该会看到一个可爱的 Tomcat 欢迎屏幕 — 如果没有的话,等待几分钟然后重试,因为网络可能需要几分钟的时间才能作出响应。
加载完页面后,单击左侧菜单的 Tomcat Manager 链接。您将被要求输入用户名和密码。输入您此前配置的用户名和密码。一旦加载管理接口,下翻到 War 文件以部署表单,单击 Browse 按钮,寻找 mytri.war。最后,单击 Deploy 按钮。这是一个庞大的 WAR 文件,因此如果部署时间过长的话,不要对此感到担心。
上传完成后,您应当会看到 mytri 应用程序已列出在 Applications 部分中。单击 mytri 应用程序链接。您应当有一种似曾相识 的感觉,因为它看上去极像 图 2 的屏幕。从这里开始,您应当能够创建新的 triathlon — 只是这一次,它们位于 Internet 某个位置中的 EC2 实例上的 MySQL 中。是不是很简单?
当您觉得一切都很满意时,不要忘记关闭 AMI。记住,Amazon 是按小时收费的(尽管费用不是很多)。您可以在 Eclipse 的 EC2 Instances 视图中右键单击实例来终止 AMI。关闭 AMI 将清除所有内容 — 也就是说,您必须重新设置 MySQL 数据库,比如,您需要再一次处理 triathlon。(另一个 Amazon 服务 Elastic Block Storage,通过允许将数据暂时保存到活动 AMI 实例中,使这些数据能够长期保存下来。)
结束语
您再一次看到了 Java 开发 2.0 的几个方面在 EC2 中体现出来:您可以在借来的基础设施上充分地利用开源包,比如 MySQL、Tomcat 和 Grails(在内部使用 Spring 和 Hibernate),这样做的成本要远远低于亲自购买硬件资源。此外,EC2 的设置非常高效,并且大大扩展了您使用自己的硬件在相同成本的条件下可以完成的功能。事实上,如果您曾经觉得自己无法实现本文介绍的这么多功能,那就对了!