Spring Roo 简介,第 3 部分: 开发 Spring Roo 的附加组件

Spring Roo 是一个 RAD 工具,支持您快速、轻松地构建应用程序(主要是 Web)。 在底层,Spring Roo 基于 OSGI 附加架构,便于通过添加附加组件扩展 Spring Roo。 Spring Roo 提供一些命令来创建附加组件,这些组件可以很容易地 提供给 Spring Roo 用户社区。在本文中,我们首先讨论了 Spring Roo 架构,讨论 Spring Roo 如何利用其自身的 附加架构来提供不同的功能,然后我们将 使用 Roo shell 创建附加组件,并对其进行修改,以满足我们的需要。

Shekhar Gulati, 高级顾问, Xebia

Shekhar Gulati 是 Xebia India 的一名 Java 顾问。他有 6 年的企业 Java 经验。他在 Spring 组合项目,比如 Spring、Spring-WS、Spring Roo 等方面拥有丰富的经验。他的 兴趣包括 Spring、NoSQL 数据库、Hadoop、RAD 框架(如 Spring Roo)、云计算(主要是 Google App Engine、 CloudFoundry、OpenShift 等 PaaS 服务)、Hadoop。他是一位活跃的作家,为 JavaLobby、Developer.com 和 IBM developerWorks 撰稿,他在 http://whyjava.wordpress.com/ 有自己的博客。



2011 年 11 月 21 日

入门

在本 “Spring Roo 简介” 系列的 Spring Roo 简介,第 1 部分:从源代码构建Spring Roo 简介,第 2 部分:使用 Spring Roo 开发应用程序,我们 使用 Spring Roo 从头开始构建了一个功能完整的企业应用程序。前两篇 文章专注于使用 Spring Roo 的快速应用开发环境构建 Web 应用程序。我们涵盖了 许多功能,如:JPA、Selenium 测试、Spring Security、电子邮件 集成、Spring Roo 社交功能、数据库逆向工程等。 现在我们将看一看 Spring Roo 的 附加架构。然后我们将使用 addon create 命令编写 Spring Roo 附加组件。到本文的最后, 您将能够快速、轻松地 创建您自己的 Spring Roo 附加组件。


Spring Roo 附加 架构

简单来说,附加组件是一种软件组件,它将 特定的功能添加到软件应用中。例如,在大多数 Web 浏览器中,视频支持由附加组件提供。另一个 示例是 Eclipse(许多 Java™ 开发人员使用或 至少了解的开源 IDE)。大多数功能, 如 JUnit 支持、SVN 支持等,都由附加组件提供。我在使用 add-on 作为 插件和扩展的总称。

Spring Roo 还有附加组件的概念:

  1. 为了让第三方开发人员能够创建扩展 Spring Roo 的功能的能力
  2. 帮助 Spring Roo 轻松添加新功能
  3. 帮助 Spring Roo 仍然轻便灵活(即:减少 Spring Roo 的大小)

Spring Roo 逻辑组件

Spring Roo 被分为两个逻辑部分。

Spring Roo 核心组件: 为了实现附加组件的开发, Spring Roo 提供了一组核心组件,这些组件构成了 不同附加组件的托管执行环境。这些组件是 Classpath,它支持 Process Manager 和 Shell。反过来,Process Manager 支持 Project 和 File Undo。Project 支持 Model、Metadata 和 File Monitor。最后,还有 Support 组件,它由所有组件使用。图 1 提供了 这些关系的可视化表示。

图 1. Spring Roo 核心 组件
图中展示了 Spring Roo 组件之间的关系

我们来讨论一些核心模块:

  • Supportorg.springframework.roo.support 模块 提供所有核心模块 和附加组件使用的常见实用工具类。一些实用工具类包括 AssertFileCopyUtilsXmlUtilsStringUtilsFileUtils 等。例如,如果您 要将一个文件的内容复制到另一个文件,您可以使用 FileCopyUtils 来完成。
  • Metadata— org.springframework.roo.metadata 模块 提供元数据服务提供程序接口和实现, 包括依赖项注册和缓存。
  • File monitor— org.springframework.roo.file.monitor 模块在检测到的文件系统变化之后公布事件 (默认实现使用自动缩放的磁盘轮询)。
  • File undo— org.springframework.roo.file.undo 模块提供文件撤消工具,供进程 管理器使用。
  • Project— org.springframework.roo.project 模块 提取典型的最终用户项目构建系统,如 Apache Maven 和 Apache Ant。
  • Process manager— org.springframework.roo.process.manager 模块提供一个类似于 ACID 的文件系统抽象,包括 磁盘回滚和进程同步。
  • Classpath— org.springframework.roo.classpath 模块对 Java 和 AspectJ 编译单元执行抽象语法树解析和类型绑定。

Spring Roo 核心组件:Spring Roo 通过附件组件提供所有 功能。Roo V1.1.3 附带的基础附加组件:

  • Add-On Creator— org.springframework.roo.addon.creator 附加组件支持轻松创建第三方 Roo 附加组件。
  • Backup— org.springframework.roo.addon.backup 附加组件允许通过键入备份对 ZIP 文件进行备份。
  • Cloud Foundry— org.springframework.roo.addon.cloud.foundry 附加组件提供了 VMware Cloud Foundry 支持。
  • Configurable— org.springframework.roo.addon.configurable 附加组件支持通过 AspectJ ITD 引入 Spring @Configurable 注释。
  • Database reverse engineering— org.springframework.roo.addon.dbre 附加组件支持 现有数据库的增量逆向工程。
  • Data on Demand— org.springframework.roo.addon.dod 附加组件支持自动创建 用于集成测试的样本数据。
  • Email— org.springframework.roo.addon.email 附加组件支持 在目标项目中集成和配置 Spring 的电子邮件支持。
  • Entity— org.springframework.roo.addon.entity 附加组件提供了扩展的支持,可自动维护 Java Persistence API @Entity 类。
  • Dynamic Finder— org.springframework.roo.addon.finder 创建类型安全的与代码完成兼容的 JPA 查询语言 查找器。
  • Git— org.springframework.roo.addon.git 附加组件提供对项目中 GIT 集成的支持。每个 成功执行的命令将自动提交到 本地 GIT 存储库。
  • GWT— org.springframework.roo.addon.gwt 附加组件支持使用 Google Web 工具包的 UI 基架。
  • JavaBean— org.springframework.roo.addon.javabean 附加组件自动维护 JavaBean getter/setter,用于 带有 @RooJavaBean 注释的类。
  • JDBC— org.springframework.roo.addon.jdbc 附加组件封装对不同捆绑包中附带的 JDBC 驱动程序的符合 OSGi 的 访问(主要由其他附加组件使用)。
  • JMS— org.springframework.roo.addon.jms 附加组件支持在目标项目中配置 Java Messaging System 设置。
  • JPA— org.springframework.roo.addon.jpa 附加组件安装指定的 JPA 提供程序,并相应地设置 JDBC 。
  • JSON— org.springframework.roo.addon.json 附加组件将与 JSON 相关的序列化和反序列化方法添加到 POJO。
  • Logging— org.springframework.roo.addon.logging 附加组件设置 Log4j,包括基于命令的日志级 配置。
  • Pluralization— org.springframework.roo.addon.plural 附加组件提供了名词复数(主要由其他 附加组件使用)。
  • Property Editor— org.springframework.roo.addon.property.editor 附加组件按 Spring MVC 的要求管理属性编辑器。
  • Property File— org.springframework.roo.addon.propfiles 附加组件支持在目标项目中管理 属性。
  • RooBot Client— org.springframework.roo.addon.roobot.client 附加组件支持通过 RooBot 服务器进行附加组件的管理。
  • Security— org.springframework.roo.addon.security 附加组件设置 Spring Security,包括登录页面、过滤器和依赖项。
  • Serializable— org.springframework.roo.addon.serializable 附加组件将 java.io.Serializable 支持(如 UID 维护) 添加到所请求的 Java 类型。
  • Solr— org.springframework.roo.addon.solr 附加组件支持在目标项目中配置和集成 Apache Solr 功能。
  • Integration Test— org.springframework.roo.addon.test 附加组件为项目实体产生 JUnit 集成测试。
  • ToString— org.springframework.roo.addon.tostring 附加组件为任何带有 @RooToString 注释的类创建一个有效的 toString() 方法。
  • WebFlow— org.springframework.roo.addon.Web.flow 附加组件支持在目标项目中配置和集成 Spring Web Flow 功能。
  • Web MVC Controller— org.springframework.roo.addon.Web.mvc.controller 附加组件支持在目标项目中配置和集成 Spring MVC 控制器。
  • Web MVC Embedded— org.springframework.roo.addon.Web.mvc.embedded 附加组件提供了对 MVC 附加组件的扩展,这允许将地图、视频等嵌入式功能添加到网页中。
  • Web MVC JSP— org.springframework.roo.addon.Web.mvc.jsp 附加组件在目标项目中配置和集成 Spring MVC JSP 功能。
  • Selenium— org.springframework.roo.addon.Web.selenium 附加组件支持在目标项目中配置和集成 Selenium Web 测试。

现在我们已经看过了 Spring Roo 核心组件以及 Spring Roo 提供的基本附加组件,接下来我们编写自己的附加组件。


OSGi 运行时 环境

Spring Roo 基于 OSGi,它是 Roo 的附加 架构的理想之选。OSGi 提供了非常好的基础架构来开发 模块化和嵌入式的面向服务应用程序。

Roo shell 使用 Apache Felix 作为其 OSGi 运行时框架,同时使用 Service Component Runtime (SCR) 进行组件管理,使用 OSGi Bundle Repository (OBR) 进行捆绑解析。在 Roo shell 中有各种 OSGi 命令,您可以通过键入 help osgi 查看,如清单 1 所示。

清单 1. 针对 OSGi 的 Roo 帮助
roo> help osgi 
* osgi find - Finds bundles by name 
* osgi framework command - Passes a command directly 
through to the Felix shell infrastructure 
* osgi headers - Display headers for a specific bundle 
* osgi install - Installs a bundle JAR from a given URL 
* osgi log - Displays the OSGi log information 
* osgi obr deploy - Deploys a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr info - Displays information on a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr list - Lists all available bundles from the 
OSGi Bundle Repository (OBR) system 
* osgi obr start - Starts a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr url add - Adds a new OSGi Bundle Repository (OBR) repository file URL 
* osgi obr url list - Lists the currently-configured 
OSGi Bundle Repository (OBR) repository file URLs 
* osgi obr url refresh - Refreshes an existing 
OSGi Bundle Repository (OBR) repository file URL 
* osgi obr url remove - Removes an existing 
OSGi Bundle Repository (OBR) repository file URL 
* osgi ps - Displays OSGi bundle information 
* osgi resolve - Resolves a specific bundle ID 
* osgi scr config - Lists the current SCR configuration 
* osgi scr disable - Disables a specific SCR-defined component 
* osgi scr enable - Enables a specific SCR-defined component 
* osgi scr info - Lists information about a specific SCR-defined component 
* osgi scr list - Lists all SCR-defined components 
* osgi start - Starts a bundle JAR from a given URL 
* osgi uninstall - Uninstalls a specific bundle 
* osgi update - Updates a specific bundle 
* osgi version - Displays OSGi framework version

Spring Roo 附加组件 创建命令

Spring Roo 绑定了附加组件创建命令,用于创建 不同类型的附加组件。Add-on Creator 公开 addon create 命令,也是一个 Roo 附加组件。 Roo 目前支持四类附加组件:

  1. Internationalization Add-on— 它 支持为 Roo 的支架式 Spring MVC 应用程序添加语言翻译(例如,添加对印地语的翻译 )。
  2. Simple Add-on— Simple Add-on 支持对 项目依赖项或配置或这两者的小增补(例如,进行 一些 maven pom.xml 修改,如添加某些 JAR 或 Maven 插件)。
  3. Advanced Add-on— 该附加组件执行繁重的工作, 用于构建功能完整的 Spring Roo 附加组件,该组件需要创建 Java 代码(构建一个能够为域对象 编写 equalshashcode 方法的附加组件。)已经有一个社区附加组件来执行这些 功能。
  4. Wrapper Add-on—该附加组件包含 一个 Maven 工件,以 创建符合 OSGi 的捆绑包。当 附加组件需要依赖项来完成其功能时需要它。 例如,Spring Roo 数据库逆向工程附加组件 需要 Postgres JDBC 驱动程序来完成任务,因此您将 使用该附加组件包装 Postgres JDBC 驱动程序。

这些附加组件创建命令来简化 Roo 附加组件的开发,通过 创建新的附加组件:

httppgp://

Spring Roo V1.1 推出了 Pretty Good Privacy (PGP),允许用户指定哪些开发人员是可信赖的,能够为可以在 Roo shell 中下载和激活的软件签名。事实上, 每个版本的 Roo 本身现在都有 PGP 签名。一种称为 httppgp:// 的新协议处理程序被引入 Roo 中,表明 URL 还具有 PGP 防护独立的签名。这提供了一种开放的安全形式,有助于 防止用户进行恶意下载。这些标准还允许使用独立的 PHP 工具来独立验证 Roo 的操作。

  • 与 Google Code SVN 源代码控制集成。
  • 在公共 Maven 存储库中托管,作为 Google 代码项目的一部分创建。
  • 符合 RooBot,一种 VMware 托管服务, 为公共 Roo OBR 文件中的重要内容编制索引。 OBR 文件是对捆绑包元数据的基于 XML 的表示。 为了符合 RooBot,附加组件应:
    1. 符合 OSGi。
    2. PGP 签名的工件,带有公共密钥。
    3. 通过 httppgp:// 协议注册。

使用 Roo addon create 命令,您能够获得 自动为您的 附加组件配置的上述所有功能。这无疑减少了创建和向外界发布 附加组件的时间。

在开始编写附加组件之前,请确保您拥有一个正在运行的 Spring Roo 环境。Spring Roo 安装说明可在 本系列的 Spring Roo 简介,第 1 部分:从源代码构建 找到。


我想要印地语支持 (i18N 附加组件创建)

当您使用 Spring Roo 创建基于 Spring MVC 的 Web 应用程序时,您 可以使用 Web mvc language 命令添加对不同语言的支持。Spring Roo 开箱即用地支持英语、德语、西班牙语、意大利语、荷兰语和 瑞典语。国际化支持由 Web MVC JSP 附加组件提供,仅当您的 Webapp 目录中有 JSPX 文件时才启用该附加组件。JSPX 文件由一个控制器命令生成, 该命令将简单的基于 JAR 的应用程序转换为 Spring MVC Web 应用程序。

作为一名印度人,我想要在我的 Web 应用程序中添加对印地语的支持。Spring Roo 提供一个 addon create i18n 命令,该命令提供 对 Web mvc install language command 的扩展,添加 对印地语等新语言的支持。它只需要 将 messages.properties 文件转换成所需的 语言。

当 Spring Roo 创建 Spring MVC Web 应用程序时,它创建两个 属性文件:application.properties 和 messages.properties。 application.properties 文件包含特定于应用程序的 属性,比如应用程序名称。messages.properties 文件 包含的属性不特定于任何应用程序, 比如当您单击删除按钮时会出现 “您确定要删除该项目吗?” 消息,还有登录、注销等消息。因此,在 编写 i18n 附加组件时,您需要提供对 messages.properties 文件的翻译。

现在,我们已经讨论了 Spring Roo 中的默认国际化支持,让我们编写能够添加印地语支持的 i18n 附加组件。 我将展示如何使用 Google 代码建立项目,使用 命令编写附加组件,并向外界发布,最后 使用 RooBot 服务注册它。使用 RooBot 服务进行注册很重要,因为这会让 RooBot 为您的附加组件编制索引 并在其他开发人员通过 addon search 命令进行搜索时显示该组件。

项目建立

Spring Roo 文档 生动地讲解了如何使用 Google 代码建立您的 项目和 Maven 存储库,因此我不会 重复。我只说明我将使用项目名称 “roo-hind-addon”。

创建一个 i18N 附加组件

在建立了项目后,您将有一个空目录, 称为 roo-hindi-addon。进入该目录并输入 roo command。在进入 shell 后,输入 addon create i18n。如果按下 tab 键,您将看到该命令接受 7 个属性。在这 7 个属性中,有 3 个属性是必选的: topLevelPackage(新附加组件的顶层包 )、locale(语言设置缩写, 如 “it” 代表意大利语)和 messageBundle (到 message_xx.properties 的完全限定路径,其中 xx 是 区域名称)。另外 4 个属性是可选属性: language(语言的全名)、 flagGraphic(到 xx.png 文件的完整路径,其中 xx 是标志名称)、description (对附加组件的说明)和 projectName(项目名称(如果没有 提供,则使用顶层包名称))。我建议 您使用 projectName 属性 并确保其值是在 Google 代码上托管的项目的名称。因此,在我们的示例中,将是 roo-hindi-addon。

在上述属性中,最重要的是 messageBundle,它指定 转换后的 messages.properties 文件。为了将 messages.properties 转换成印地语,最简单的方法是使用 Google translate 等服务,依次转换每个属性,然后 将它们写入到 messages_hi.properties 文件。然而,这在 我们的情况下不可行,因为 Java 属性文件使用 ISO-8859-1 编码,不支持印地文字符。为了克服这个问题,我使用了一个称为 Eclipse ResourceBundle Editor 的 Eclipse 插件,它允许您为不同语言转换并创建资源 包。您可以使用 http://www.nightlabs.de/updatesites/development/ 更新站点安装它。 将 messages.properties 文件转换为 messages_hi.properties 文件不在本文的讨论范围内。ResourceBundle Editor 插件易于使用。请注意,如果支持该语言 字符,则不需要使用 ResourceBundle Editor。messages_hi.properties 文件看起来与 清单 2 类似。

清单 2. messages_hi.properties 文件示例
button_cancel = \u0930\u0926\u094D\u0926 
button_end = \u0905\u0902\u0924
button_find = \u0916\u094B\u091C\u0947\u0902
button_home = \u0918\u0930 
...

查看 full file。一旦您拥有了转换后的 messages_hi.properties 文件,您便可以创建该附加组件,只需 输入一个命令便能完成。您可以通过 将清单 3 中的命令输入到 Roo shell 中来创建印地语附加组件,。

清单 3. 创建印地语附加组件的命令
addon create i18n --locale hi --topLevelPackage org.xebia.roo.addon.i18n.hindi 
  --messageBundle <location to messages_hi.properties> \
--language hindi --projectName roo-hindi-addon 
  --flagGraphic <full path to flag hi.png>

清单 4 显示了通过 addon create i18n 命令创建的工件。

清单 4. 创建的工件
Created ROOT/pom.xml 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SRC_MAIN_WEBAPP 
Created SRC_MAIN_RESOURCES/META-INF/spring 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/messages_hi.properties 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/hi.png 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi/HindiLanguage.java

该命令生成了一个 Maven 项目,可以通过 File > Import > Maven > Existing Maven projects 导入到 Eclipse(有 m2eclipse)或 SpringSource 工具套件。您不需要 导入该项目,因为我们不需要修改该附加组件。

现在我们可以安装该附加组件,在我们的项目中使用它,并将其对外发布。但是,首先我们讨论一些 工件,以更多地了解生成的代码:

  • pom.xml 是一个标准的 Maven 项目 配置。所生成的 pom.xml 有各种预配置的 插件,它们执行与使用 PGP 对工件进行签名的工作,使用 Maven 版本插件发行该附加组件, 使用 Maven 捆绑包插件创建 OSGi 捆绑包。它还将 OSGi 和 Felix 依赖项添加到项目中,这是让 附加组件在 Roo shell 内运行所必需的。
  • assembly.xml 定义了由 Maven 程序集插件用来包装附加组件的配置。
  • messages_hi.properties 是在创建附加组件时我们提供的消息包 文件,被复制到 资源文件夹。
  • hi.png 是在创建附加组件时我们提供的标志 PNG 文件,被复制到资源 文件夹。
  • HindiLanguage.java 是该附加组件所创建的惟一的 Java 文件, 用于获取对应于 特定语言的信息。例如,它提供本地名称、 消息包资源文件等。

将印地语支持添加到 应用程序

现在我将向您展示如何 使用我们刚刚创建的附加组件将印地语支持添加到您的应用程序:

  1. 退出 Roo shell 并运行 mvn clean install 命令。在构建过程中,它会询问您的 GPG 密码。
  2. 在构建了 Roo 附加组件后,打开新的命令行 并创建名为 i18n-hindi-client 的目录。我们将为我们的附加组件创建一个 简单的客户端。
  3. 进入 i18n-hindi-client 目录并输入 roo 命令。
  4. 在 Roo shell 中执行以下命令。这将创建 一个简单的 Spring MVC Web 应用程序。
    清单 5. 创建 MVC Web 应用程序的 Roo 命令
    project --topLevelPackage com.shekhar.roo.i18n.client \
    --projectName i18n-hindi-client  
    persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY  
    entity --class ~.domain.MyUser  
    field string --fieldName name --notNull  
    controller all --package ~.web
  5. 输入该命令并按下 Tab 键:Web mvc language --code de en es it nl sv

    您不会看到印地语支持。这是因为我们 还没有安装印地语附加组件。

  6. 要安装该附加组件,请输入:
    osgi start --url file:///<location to addon target 
       folder>/org.xebia.roo.addon.i18n.hindi-0.1.0.BUILD-SNAPSHOT.jar

    这样应该便能够安装并激活我们的 Spring Roo 印地语附加组件。 您可以使用 osgi ps 命令查看该附加组件的状态,这会显示 OSGi 包信息及其状态,如下所示:

    [ 95] [Active ] [ 1] roo-hindi-addon (0.1.0.BUILD-SNAPSHOT)
  7. 再次输入 Web mvc language –code 并按下 Tab 键。这次,您将看到针对印地语的 代码。选择 hi 代码,印地语支持将被 添加到您的应用程序。
    Web mvc language –code hi
  8. 退出 Roo shell 并输入 mvn tomcat:run。您将在 页脚看到印度国旗。单击该国旗,您的应用程序 将用印地语显示出来,如图 2 所示。
    图 2. 印地语支持
    屏幕快照显示在浏览器中运行的应用程序,有多个文本项以印地语显示

在测试了该附加组件在您的 开发系统中运行良好后,您可以将该附加组件推送到 我们创建的 Google 代码项目。

高级选项

现在我们已经看到我们创建的附加组件运行正常,让我们 看一下如何将印地语提供给 应用程序:

  1. roo-hindi-addon 通过 osgi start 命令启动。
  2. 在附加组件启动后,由 addon create i18n command 创建的 HindiLanguage 类在 i18nComponent 上得到注册。i18nComponent 是一个 OSGi 服务侦听器, 用于注册和注销 i18n 附加组件。 HindiLanguage 类标有 @Component@Service 注释,这由 Apache Felix 提供。这些注释确保在 Roo shell 上注册了这些组件和 服务,且它们可供 使用。
  3. 当我们输入 Web mvc install language –code 命令 并按下 tab 键后,tab 完成服务将调用 i18nComponent 类 getSupportedLanguages() 方法,这将 返回 i18n 附加组件的 java.util.Set。 因为 HindiLanguage 已经 在 i18nComponent 上进行了注册,因此也会返回它。

对外发布 附加组件

对外发布附加组件非常容易,因为 Roo create 命令已经通过安装所有必需的 Maven 插件为我们完成了大多数操作。转到 项目根目录,并输入清单 6 中的命令。

清单 6. 发布 Roo 项目
svn add pom.xml src/ legal/ readme.txt 
svn commit -m "Roo Hindi Addon first version" 
mvn release:prepare release:perform

Maven 版本插件会要求输入发行版本、标记名称以及 开发版本。您可以只选择默认设置,然后继续。 发行和发布工件到 Google 代码项目需要几分钟的时间。然后您可以 在您的 Google 代码项目中查看这些附加工件。

在 RooBot 上注册您的附加组件

在发布了插件后,您可以通过电子邮件将它发送到 s2-roobot@vmware.com 来注册您的附加组件存储库。 电子邮件的主题行必须包含 repository.xml 文件。例如, 对于我们刚刚创建的附加组件,repository.xml 为 http://code.google.com/p/roo-hindi-addon/source/browse/repo/repository.xml。 如需了解关于 RooBot 注册的更多信息,请参见 Spring Roo 文档


我想要监控我的 Java 应用程序(简单的附加组件创建)

许多企业应用程序中的一个常见要求就是监控 Java 应用程序来确定应用程序的 性能瓶颈。我也有同样的要求,因此我决定 看一下一些可用的开源解决方案。Java Application Monitor (JAMon) 是免费的、高性能、线程安全的 Java API,使您能够轻松监控生产 应用程序。

要在您的 Web 应用程序中添加 JAMon 支持:

  1. 您必须在您的 pom.xml 中添加 jamon JAR。
  2. 您必须在您的应用程序上下文文件中定义 JamonPerformanceMonitorInterceptor bean。 示例 bean 定义与 清单 7 中的代码类似。
清单 7. JamonPerformanceMonitorInterceptor 代码
	<bean id="jamonPerformanceMonitorInterceptor" 
		class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> 
		<property name="trackAllInvocations" value="true"></property> 
		<property name="useDynamicLogger" value="true"></property> 
	</bean> 

	<bean id="autoProxyCreator" 
		class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
		<property name="interceptorNames"> 
			<list> 
				<idref bean="jamonPerformanceMonitorInterceptor" /> 
			</list> 
		</property> 
		<property name="beanNames"> 
			<list> 
				<value>speakerController</value> 
				<value>talkController</value> 
			</list> 
		</property> 
	</bean>

这不是任何开发人员都能够轻松铭记的简单的 bean 定义, 我认为如果我可以自动化该 样板配置会很不错。因此我决定编写一个附加组件,它能够 自动化添加 JAMon 依赖项和连接 侦听器 bean 的流程。您如何决定您需要简单还是高级 附加组件呢?

  1. 当您想要将 Maven 依赖项、配置工件或这两者添加到您的 项目时,使用简单附加组件
  2. 当您需要编写增强现有 Java 类型的 功能完整的附加组件、引入 新的 Java 类型和 AspectJ ITD 或同时实现这两点时,使用高级附加组件

我们的要求是将 jamon.jar 添加到类路径,并编写 包含我们的 bean 定义的应用程序上下文文件。最好 编写一个新的 Spring 应用程序上下文文件,而不是 使用现有的上下文文件,因为这有助于模块化 应用程序上下文。根据这些要求,显然 我们应该编写简单的附加程序,能够将 JAMon 支持添加到任何 Web 应用程序。

项目建立

我们需要以与国际化附加组件相同的方式建立项目。我将该项目命名为 “spring-roo-addon-jamon”。

创建简单的 附加组件

在建立了项目后,您将得到一个名为 spring-roo-addon-jamon 的目录以及 .svn 文件夹。转到 spring-roo-addon-jamon 目录并启动 Spring Roo shell。然后 输入下面的命令:

addon create simple --topLevelPackage org.xebia.roo.addon.jamon \
--projectName spring-roo-addon-jamon

好!附加组件创建完成。

安装生成的 附加组件

您可以通过下面的命令安装该附加组件:

osgi start --url file://<Location to addon
    target folder>/org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

在安装了附加组件后,创建一个要测试的简单客户端,正如我们 为 i18n 附加组件所创建的。生成的附加组件提供两个 命令:

  1. say hello,该命令在 Roo shell 上打印出一条欢迎消息。该命令将总是可用,您可以 在 Roo shell 运行时随时输入该命令。
  2. Web mvc install tags 取代了默认 MVC 标记, 当您构建 Web 应用程序时会生成该标记。该命令 只能在您创建了 Web 应用程序后才可用。

看一看生成的 代码

现在您已经测试了该附加组件,让我们看一看 该附加组件生成的文件,如清单 8 所示。

清单 8. 为 spring-roo-addon-jamon 生成的文件
Created ROOT/pom.xml 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SRC_MAIN_WEBAPP 
Created SRC_MAIN_RESOURCES/META-INF/spring 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonCommands.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperations.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperationsImpl.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonPropertyName.java 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/info.tagx 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/show.tagx

文件 pom.xml、assembly.xml、LICENSE.TXT 和 readme.txt 与 i18n 附加组件所生成的相同。我们在前面已经讨论了这些文件,因此 我不会再次讨论。比较有趣的工件包括 JamonCommands、JamonOperations、 JamonOperationsImpl 和 JamonPropertyName。我们将逐个进行讨论, 以了解简单的 附加组件命令生成的代码。

  1. JamonCommands.java:JamonCommands— 这个类实现了一个称为 CommandMarker 的标记接口,并公开了两个命令,say hello 和 Web mvc install 标记,如清单 9 所示。
    清单 9. JamonCommands.java:JamonCommands 生成的代码
    @Component 
    @Service 
    public class JamonCommands implements CommandMarker { 
            
           @Reference private JamonOperations operations; 
            
           @Reference private StaticFieldConverter staticFieldConverter; 
    
    
           protected void activate(ComponentContext context) { 
               staticFieldConverter.add(JamonPropertyName.class); 
               } 
    
    
           protected void deactivate(ComponentContext context) { 
                   staticFieldConverter.remove(JamonPropertyName.class); 
           } 
            
           @CliAvailabilityIndicator("say hello") 
           public boolean isSayHelloAvailable() { 
                   return true; 
           } 
            
           @CliCommand(value = "say hello", 
    help = "Prints welcome message to the Roo shell") 
           public void sayHello( 
                   @CliOption(key = "name", mandatory = true, 
    help = "State your name") String name, 
                   @CliOption(key = "contryOfOrigin", mandatory = false, 
           help = "Country of origin") JamonPropertyName country) { 
                    
                   log.info("Welcome " + name + "!"); 
                   log.warning("Country of origin: " + (country == null ? \
    JamonPropertyName.NOT_SPECIFIED.getPropertyName() : country.getPropertyName())); 
                   
                   log.severe("It seems you are a running JDK " 
    + operations.getProperty("java.version")); 
                   log.info("You can use the default JDK logger anywhere in your" 
    + " add-on to send messages to the Roo shell"); 
           } 
            
           @CliAvailabilityIndicator("web mvc install tags") 
           public boolean isInstallTagsCommandAvailable() { 
                   return operations.isInstallTagsCommandAvailable(); 
           } 
            
           @CliCommand(value = "web mvc install tags", 
    help="Replace default Roo MVC tags used for scaffolding") 
           public void installTags() { 
                   operations.installTags(); 
           } 
    }

    我已经删除了代码生成器所生成的所有注释, 以减少代码的冗余。让我们看看 这个类的重要成员:

    1. CommandMarker— 所有命令类 都应该实现 CommandMarker 接口,并 通过 @Component@Service 注释注明,以便对它们 进行注册并让它们的命令在 Roo shell 中可用。通过 @Reference 注释的字段是 JamonCommands 类的依赖项,通过 底层 Roo OSGi 容器注入。所有使用 @Component@Service annotations 注释的类都可以 被注入到其他附加组件。
    2. Activate 和 Deactivate 方法activatedeactivate 方法是 在您使用 addon install 命令安装附加组件或使用 addon remove 命令删除附加组件时调用的方法。这些方法允许您挂接到 附加组件的生命周期,这通过底层 Roo OSGi 容器管理。
    3. 标有 @CliAvailabilityIndicator 注释的方法— 标有 @CliAvailabilityIndicator 注释的方法是 在命令不可用时帮助隐藏命令的方法。 例如,security setup 命令,它将 Spring Security 安装到项目中,除非该项目是一个 Web 应用程序,否则它不可见。不要求 您必须拥有这些方法,但是它们非常有用, 因为它们不允许用户发出 当时没有意义的命令。例如,在用户拥有 Web 应用程序之前执行 security setup 命令就没有 任何意义。
    4. 标有 @CliCommand 注释的方法— 标有 @CliCommand 注释的方法将命令注册在 Roo shell 中。 @CliCommand 注释有两个 属性:value, 它定义命令名称,和 help,它定义帮助 消息,当您输入 help 命令时会显示帮助消息。每个命令都能够 使用 @CliOption 注释定义强制性和非强制性属性,作为 该命令的一部分。例如, say hello 命令有一个称为 name 的强制性 属性和一个称为 country 的 非强制性属性。
  2. JamonOperationsImpl.java— 在执行某个命令时命令类需要执行某些操作。这些操作由 操作类执行。JamonOperationsImpl 是一个操作类,负责执行实际 工作,比如在 pom.xml 中添加依赖项,或将资源复制到 所需的位置。 JamonOperationsImpl 使用 Spring Roo 框架提供的核心服务执行其操作。例如,要添加一个依赖项,它使用 ProjectOperations 接口。要复制 文件,它则使用 FileManager 接口。让我们看看 JamonOperationsImpl 类的代码(参见清单 10) 以便更好地了解 Roo 附加组件。
    清单 10. JamonOpertionsImpl
    	@Component 
    	@Service 
    	public class JamonOperationsImpl implements JamonOperations { 
    		private static final char SEPARATOR = File.separatorChar; 
    	 
    		@Reference private FileManager fileManager; 
    		@Reference private ProjectOperations projectOperations; 
    
    		public boolean isInstallTagsCommandAvailable() { 
    			return projectOperations.isProjectAvailable() &&
                fileManager.exists(projectOperations.getProjectMetadata().
    			getPathResolver().getIdentifier(Path.SRC_MAIN_WEBAPP,
                    "WEB-INF" + SEPARATOR + "tags")); 
    	} 
    
    		public String getProperty(String propertyName) { 
    			Assert.hasText(propertyName, "Property name required"); 
    			return System.getProperty(propertyName); 
    		} 
    
    		public void installTags() { 
    			PathResolver pathResolver =
                projectOperations.getProjectMetadata().getPathResolver(); 
    			createOrReplaceFile(pathResolver.getIdentifier(
    			    Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +
                        "tags" + SEPARATOR + "util"), "info.tagx"); 
    
    		createOrReplaceFile(pathResolver.getIdentifier(
    			Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +
                    "tags" + SEPARATOR + "form"), "show.tagx"); 
    		} 
    	 
    		private void createOrReplaceFile(String path, String fileName) { 
    			String targetFile = path + SEPARATOR + fileName; 
    			MutableFile mutableFile = fileManager.exists(targetFile) ?
                    fileManager.updateFile(targetFile) :
                    fileManager.createFile(targetFile); 
    			    try { 
    			    	FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),
                            fileName), mutableFile.getOutputStream()); 
    			    } catch (IOException e) { 
    				throw new IllegalStateException(e); 
    			} 
    		} 
    	}

    JamonOperationsImpl 类有两个 重要的方法: isInstallTagsCommandAvailable 检查该命令是否可用, installTags 将标记安装到 目标项目。为了执行这些操作, JamonOperationsImpl 类使用一些 Spring Roo 核心服务和实用程序:

    1. ProjectOperations : JamonOperationsImpl 类使用 ProjectOperations 服务来 检查项目是否可用,并获得 标记文件夹的路径。
    2. FileManager : JamonOperationsImpl 类使用 FileManager 服务来检查一个文件是否在某个路径上存在, 并获得更新或创建一个 MutableFileMutableFile 是另一个特定于 Roo 的类,它表示一个 可以进行修改的文件的句柄。
    3. TemplateUtils : TemplateUtils 实用程序类用于在我们的附加组件包里为模板文件(info.tagx 和 show.tagx)获取一个 InputStream
    4. FileCopyUtils : FileCopyUtils 实用程序类用于将模板(从 TemplateUtils)复制到 MutableFile(从 FileManager)。

修改附加组件以满足我们的 要求

在关于简单附加组件的小节中,我们讨论了两个 必须满足的要求,以便使我们的附加组件能够在任何 Spring MVC Web 应用程序中配置 JAMon。要求如下:

  1. 在您的 pom.xml 中添加 JAMon JAR
  2. 在应用程序上下文文件中定义 JamonPerformanceMonitorInterceptor bean

为了满足这些要求,我们将更改 JamonCommands 类,以支持 jamon setup 命令。然后我们将添加一个 对应于 jamon setup 命令的操作来执行实际工作,以满足要求。

JamonCommandsJamonCommands 类 现在只有两个方法:isInstallJamon 检查 jamon setup 命令是否可用, installJamon 用于在触发 jamon setup 命令时安装 JAMon。 (参见清单 11。)

清单 11. JamonCommands 的代码
@Component 
@Service 
public class JamonCommands implements CommandMarker { 
	 
	private Logger log = Logger.getLogger(getClass().getName()); 

	@Reference private JamonOperations operations; 
	 
	@CliAvailabilityIndicator("jamon setup") 
	public boolean isInstallJamon() { 
		return operations.isInstallJamonAvailable(); 
	} 
	 
	@CliCommand(value = "jamon setup", help = "Setup Jamon into your project") 
	public void installJamon() { 
		operations.installJamon(); 
	} 
}

这是我们在 JamonCommands 类中所需要的。 它只需要公开 jamon setup 命令,剩下的工作委托 JamonOperationsImpl 类完成。(参见清单 12。)

清单 12. JamonOperationsImpl 的代码
JamonOperationsImpl

JamonOperationsImpl need to implement two methods – \
isInstallJamonAvailable() and installJamon(). 

The isinstallJamonAvailable() method returns a boolean indicating whether 
command is available at this location or not. I want to enable JAMon only for the web
applications so we need to perform the check whether the project is 
a web application or not. To do that we will write the code as shown below 

	public boolean isInstallJamonAvailable() { 
		return projectOperations.isProjectAvailable() &&
        fileManager.exists(projectOperations.getPathResolver()
			.getIdentifier(Path.SRC_MAIN_WEBAPP, "/WEB-INF/web.xml")); 
	}

清单 12 中显示的代码使用 ProjectOperations 服务检查项目在该位置是否可用,以获得 web.xml 文件的路径(web.xml 文件只对 Web 应用程序存在)。FileManager 服务用于检查 Web.xml 是否在 ProjectOperations 指定的位置存在。

我们需要实现的第二个方法是 installJamon(),它应当在 pom.xml 中添加 JAMon 依赖项,并将 bean 定义添加到 Webmvc-config.xml。在编写该方法的代码之前,我们必须 在 src/main/resources/org/xebia/roo/addon/jamon 文件夹内创建一个名为 configuration.xml 的 XML 文件。该文件夹 结构是 org/xebia/roo/addon/jamon,与 您的 Roo 附加组件的包结构相同。configuration.xml 定义 JAMon 版本 和 JAMon JAR 依赖项,如清单 13 所示。

清单 13. configuration.xml 的内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<configuration> 
    <jamon> 
        <properties> 
            <jamon.version>2.4</jamon.version> 
        </properties> 
        <dependencies> 
            <dependency> 
            <groupId>com.jamonapi</groupId> 
            <artifactId>jamon</artifactId> 
            <version>${jamon.version}</version> 
        </dependency> 
        </dependencies> 
    </jamon> 
</configuration>

下面我们编写在 pom.xml 中添加依赖项的代码,如清单 14 所示。

清单 14. pom.xml 的内容
	public void installJamon() { 
		Element configuration = XmlUtils.getConfiguration(getClass()); 
		updatePomProperties(configuration); 
		updateDependencies(configuration); 
	} 

	private void updatePomProperties(Element configuration) { 
		List<Element> properties = \
XmlUtils.findElements("/configuration/jamon/properties/*"
		, configuration); 
		for (Element property : properties) { 
			projectOperations.addProperty(new Property(property)); 
		} 
	} 

	private void updateDependencies(Element configuration) { 

		List<Dependency> dependencies = new ArrayList<Dependency>(); 
		List<Element> jamonDependencies = XmlUtils.findElements(
			"/configuration/jamon/dependencies/dependency", configuration); 
		for (Element dependencyElement : jamonDependencies) { 
			dependencies.add(new Dependency(dependencyElement)); 
		} 
		projectOperations.addDependencies(dependencies); 
	}

这是在 pom.xml 中添加依赖项的标准机制,您可以 在大多数 Roo 附加组件中找到它。清单 14 中所示的代码很显而易见,使用 Spring Roo 实用程序类 XmlUtils 读取 configuration.xml 中的内容,然后使用 ProjectOperations 服务更新 pom.xml 文件。

在添加了 pom.xml 依赖项之后,我们需要创建一个单独的 Spring 配置,即 web-jamon-config.xml,它包含 JamonPerformanceMonitorInterceptor 的 bean 定义。

清单 15. web-jamon-config.xml 的内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:mvc="http://www.springframework.org/schema/mvc" \
xmlns:p="http://www.springframework.org/schema/p" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation=\
"http://www.springframework.org/schema/beans \
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
	http://www.springframework.org/schema/context \
http://www.springframework.org/schema/context/spring-context-3.0.xsd     
	http://www.springframework.org/schema/mvc \
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 


	<bean id="jamonPerformanceMonitorInterceptor" 
		class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> 
		<property name="trackAllInvocations" value="true"></property> 
		<property name="useDynamicLogger" value="true"></property> 
	</bean> 

	<bean id="autoProxyCreator" 
		class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
		<property name="interceptorNames"> 
			<list> 
				<idref bean="jamonPerformanceMonitorInterceptor" /> 
			</list> 
		</property> 
		<property name="beanNames"> 
			<list> 
				<value></value> 
			</list> 
		</property> 
	</bean> 

</beans>

在清单 15 所示的 web-jamon-config.xml 文件中,我们已经配置了 基于 Spring 的应用程序中的 JAMon 所需的一切。 我惟一没有指定的是 要监控的 bean 的名称。代码生成器无法预测 这个,因此需要附加组件开发人员进行指定。

现在我们需要编写将该 web-jamon-config.xml 文件复制到 web_INF/spring 文件夹的代码,webmvc-config.xml 也在该文件夹中,还要编写 add import 语句的代码,该语句在 webmvc-config.xml 中要导入 web-jamon-config.xml(参见清单 16)。

清单 16. 操作 pom.xml 的代码
public void installJamon() { 
		 
	// update pom.xml code 
	PathResolver pathResolver =
        projectOperations.getProjectMetadata().getPathResolver(); 
	String resolvedSpringConfigPath = pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP,
        "/WEB-INF/spring"); 
	if (fileManager.exists(resolvedSpringConfigPath + "/web-jamon-config.xml")) { 
			return; 
	} 
	copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); 
		 
	String webMvcConfigPath = resolvedSpringConfigPath + "/webmvc-config.xml"; 

	new XmlTemplate(fileManager).update(webMvcConfigPath, new DomElementCallback() { 
		public boolean doWithElement(Document document, Element root) { 
			if (null ==
               XmlUtils.findFirstElement\
("/beans/import[@resource='web-jamon-config.xml']",
                   root)) { 
                   Element element = document.createElement("import"); 
		        element.setAttribute("resource", "web-jamon-config.xml"); 
				root.appendChild(element); 
		        return true; 
		    } 
		    return false; 
		   } 
	}); 
		 
} 
	 
private void copyTemplate(String templateFileName, String resolvedTargetDirectoryPath) { 
	
    try { 
	    FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),
               templateFileName), fileManager.createFile(
	            resolvedTargetDirectoryPath + "/" +
                   templateFileName).getOutputStream()); 
	} catch (IOException e) { 
           throw new IllegalStateException(
               "Encountered an error during copying of resources for Jamon addon.", e); 
    } 
}

上面使用的 XmlTemplate 类来自于 Spring Web flow 附加组件。因此您需要将 Web flow 附加组件的依赖项添加到您的附加组件中(参见清单 17)。

清单 17. 添加 Web flow 附加组件的依赖项
<dependency> 
		<groupId>org.springframework.roo</groupId> 
		<artifactId>org.springframework.roo.addon.web.flow</artifactId> 
		<version>${roo.version}</version> 
      		<type>bundle</type> 
	</dependency>

在清单 17 中,roo.version 是 您所使用的 Roo 的版本。

我们在该附加组件中需要做的最后一件事是配置项目日志, 并设置要跟踪的日志级别。这通过 LoggingOperations 完成,它是 log4j 附加组件的操作类。要使用该 类,我们首先需要在 pom.xml 文件中添加日志附加依赖项,如清单 18 所示。

清单 18. 添加日志附加依赖项的 XML 代码
	<dependency> 
		<groupId>org.springframework.roo</groupId> 
		<artifactId>org.springframework.roo.addon.logging</artifactId> 
		<version>${roo.version}</version> 
      		<type>bundle</type> 
	</dependency>

在 pom.xml 中添加了依赖项之后,使用以下代码行将 LoggingOperation 添加到 JamonOperationsImpl 类中:

@Reference private LoggingOperations loggingOperations;

下一步,将下面的代码添加到 installJamon 方法:

loggingOperations.configureLogging(LogLevel.TRACE, LoggerPackage.PROJECT);

这是我们需要为该附加组件编写的所有代码。 JamonOperationsImpl 类的完整代码如 清单 19 所示。

清单 19. JamonOperationsImpl 的完整代码
@Component 
@Service 
public class JamonOperationsImpl implements JamonOperations { 
       @Reference private FileManager fileManager; 
       @Reference private ProjectOperations projectOperations; 
       @Reference private LoggingOperations loggingOperations; 


       public boolean isInstallJamonAvailable() { 
               return projectOperations.isProjectAvailable() && 
fileManager.exists(projectOperations.getPathResolver()
.getIdentifier(Path.SRC_MAIN_WEBAPP,"/WEB-INF/web.xml")); 
       } 


       public void installJamon() { 
               Element configuration = XmlUtils.getConfiguration(getClass()); 
               updatePomProperties(configuration); 
               updateDependencies(configuration); 
               PathResolver pathResolver = 
projectOperations.getProjectMetadata().getPathResolver(); 
               String resolvedSpringConfigPath = 
pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, 
            "/WEB-INF/spring"); 
               if (fileManager.exists(resolvedSpringConfigPath 
+ "/web-jamon-config.xml")) { 
                       return; 
               } 


               copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); 
                
               String webMvcConfigPath = resolvedSpringConfigPath 
+ "/webmvc-config.xml";


               new XmlTemplate(fileManager).update(webMvcConfigPath, 
new DomElementCallback() { 
                       public boolean doWithElement(Document document, Element root) {
                            if (null == XmlUtils.findFirstElement(
"/beans/import[@resource='web-jamon-config.xml']",
root)) { 
                                 
Element element = document.createElement("import"); 
                                element.setAttribute("resource", "web-jamon-config.xml"); 
                                root.appendChild(element); 
                                return true; 
                             } 
                             return false; 
                       } 
               });
               loggingOperations.configureLogging(LogLevel.TRACE, 
LoggerPackage.PROJECT); 
       } 
        
       private void copyTemplate(String templateFileName, 
String resolvedTargetDirectoryPath) { 
               try { 
FileCopyUtils.copy(
      TemplateUtils.getTemplate(getClass(), templateFileName),
              fileManager.createFile(resolvedTargetDirectoryPath + "/" + 
              templateFileName).getOutputStream()); 
               } catch (IOException e) { 
                       throw new IllegalStateException(
               "Encountered an error during copying of resources for Jamon addon.", e);
               } 
       } 
        
       private void updatePomProperties(Element configuration) { 
               List<Element> properties = XmlUtils
     .findElements("/configuration/jamon/properties/*",configuration);
               for (Element property : properties) { 
                       projectOperations.addProperty(new Property(property));
               } 
       } 


       private void updateDependencies(Element configuration) { 
               List<Dependency> dependencies = new ArrayList<Dependency>(); 
               List<Element> jamonDependencies = XmlUtils.findElements(
           "/configuration/jamon/dependencies/dependency", configuration); 
               for (Element dependencyElement : jamonDependencies) { 
                       dependencies.add(new Dependency(dependencyElement)); 
               } 
               projectOperations.addDependencies(dependencies); 
       } 
        
}

您可以从 Google 代码库 下载该附加组件的完整源代码。现在我们使用刚刚创建的附加组件将 JAMon 支持添加到我们的应用程序:

  1. 退出 roo shell 并运行 mvn clean install 命令。在 构建过程中,它会询问 GPG 密码。
  2. 在构建完 Roo 附加组件后,打开一个新命令行 并创建一个名为 jamon-client 的目录。我们将 为我们的附加组件创建一个简单的客户端。
  3. 转到目录 jamon-client 并输入 roo 命令,以打开 Roo shell。
  4. 在 Roo shell 中执行清单 20 中的命令。这会 创建一个简单的 Spring MVC Web 应用程序。
    清单 20. 创建简单的 MVC Web 应用程序
    project --topLevelPackage com.shekhar.roo.jamon.client --projectName jamon-client 
    persistence setup --provider HIBERNATE --database
    HYPERSONIC_IN_MEMORY
    entity --class ~.domain.MyUser
    field string --fieldName name --notNull
    controller all --package ~.web
  5. 要安装该附加组件,请输入:
    osgi start --url <a
    href="../../../../">file:///</a><location \
    to addon target folder >
    /org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

    这样能够安装并激活我们的 JAMon 附加组件。您可以 使用 osgi ps 命令查看该附加组件的状态。

  6. 输入 jamon setup 命令,您将 看到在您的应用程序中配置的 JAMon。如果您现在 使用 mvn tomcat:run 运行您的应用程序,您在控制台不会看到任何 日志,因为您还没有配置任何要监控的 bean。 让我们在 web-jamon-config.xml 中使用清单 21 中的代码配置我们的 myUserController bean。
    清单 21. web-jamon-config.xml 中 myUserController 的配置
    <bean id="autoProxyCreator" 
    		class=\
    "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
    		<property name="interceptorNames"> 
    			<list> 
    				<idref bean="jamonPerformanceMonitorInterceptor" /> 
    			</list> 
    		</property> 
    		<property name="beanNames"> 
    			<list> 
    				<value>myUserController</value> 
    			</list> 
    		</property> 
    	</bean>
  7. 现在使用 mvn tomcat:run 运行该应用程序,您将在 您的 maven 控制台看到 JAMon 日志。示例如清单 22 所示。
    清单 22. 示例 JAMon 日志
    TRACE MyUserController - JAMon performance statistics for method 
    [MyUserController.populateMyUsers]: 
    JAMon Label=MyUserController.populateMyUsers, Units=ms.: (LastValue=187.0, 
    Hits=1.0, Avg=187.0, Total=187.0, Min=187.0, Max=187.0, Active=0.0, Avg 
    Active=1.0, Max Active=1.0, First Access=Wed May 18 15:33:41 IST 2011, Last 
    Access=Wed May 18 15:33:41 IST 2011)

在测试过您的附加组件在您的 开发系统中运行良好后,您可以将其推送到我们 创建的 Google 代码项目中。要对外发布附加组件,请遵循 我们用来发布 i18n 附加组件的过程。同样,要 在 RooBot 上注册该附加组件,请遵循 i18n 注册过程。


结束语

我们探究了 Spring Roo 附加架构,以及如何 编写国际化和简单的附加组件。附加架构 对于 Roo 非常重要,因为它为 Roo 提供了 快速添加新功能的灵活性。对于开发人员来说,该附加架构 非常重要,因为它能够满足他们的要求而无需 等待功能在全局实现。过些时候,如果将 一个功能纳入到 Roo 中,可以相对容易地改变 实现来删除自定义解决方案。

在该 “ Spring Roo 简介” 系列的第 4 部分,我将讨论如何编写高级的包装附加组件。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source
ArticleID=775945
ArticleTitle=Spring Roo 简介,第 3 部分: 开发 Spring Roo 的附加组件
publish-date=11212011