第 7 章 配置模块

7.1. 介绍

7.1.1. 模块

模块是用于类加载和依赖关系管理的类的逻辑组。JBoss EAP 6 使用两种模块类型,有时称为静态和动态模块。然而,这两者的区别只是它们打包的方式。所有模块都提供相同的功能。
静态模块
静态模块是在应用服务器的 EAP_HOME/modules/ 目录里进行预定义的。每个子目录都代表一个模块并包含一个配置文件(module.xml)或所需的 JAR 文件。模块的名称是在 module.xml 文件里定义的。所有应用服务器提供的 API 都是作为静态模块提供的,包括 Java EE API 以及其他 API(如 Jboss Logging)。

例 7.1. module.xml 文件示例

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="com.mysql">
  <resources>
    <resource-root path="mysql-connector-java-5.1.15.jar"/>
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>

模块名 com.mysql 应该匹配这个模块的目录结构。
JBoss EAP 里提供的模块位于 JBOSS_HOME/modules 里的 system 目录。这使它们和第三方体的模块隔离开来。
Red Hat 提供的任何高于 JBoss EAP 6.1 或更高版本的分层产品也会安装它们的模块到 system 目录里。
如果许多使用相同第三方库的应用程序部署在相同的服务器上,那么创建自定义静态模块就很有用。不是将这些库捆绑到每个应用程序,而是由 JBoss 管理员创建和安装包含这些库的模块。然后应用程序就可以声明对自定义静态模块的显性依赖关系。
用户必须确保使用一个目录对应一个模块的格式将自定义的模块安装至 JBOSS_HOME/modules 目录。这可以确保系统加载已存在于 system 目录的模块的自定义版本,而不是系统附带的版本。因此,用户提供的模块将优先于系统模块。
如果您使用 JBOSS_MODULE_PATH 环境变量来修改 JBoss EAP 搜索模块的位置,那么产品将查找指定的位置中的 system 子目录结构。system 结构必须存在于用 JBOSS_MODULE_PATH 指定的位置中的某处。
动态模块
应用服务器为每个 JAR 或 WAR 部署(或 EAR 里的子部署)创建和加载动态模块。动态模块的名称源自部署的归档的名称。因为部署是作为模块加载的,它们可以配置依赖关系并被其他部署作为依赖关系使用。
模块只有在需要时才会加载。这通常只在具有显性或隐性依赖关系的应用程序部署时发生。

7.1.2. 全局模块

全局模块(Global Module)是 JBoss EAP 6 作为每个应用程序的依赖关系而提供的模块。将任何模块添加到应用服务器的全局模块列表里都可以使其成为全局模块,你并不需要修改模块。

7.1.3. 模块的依赖关系

模块依赖关系是某个模块要求另外一个模块的类行使功能的声明。模块可以声明对多个模块的依赖关系。当应用服务器加载一个模块时,模块类加载器将解析该模块的依赖关系并从每个依赖关系中添加类到 class path 里。如果无法找到指定的依赖关系,这个模块将加载失败。
部署的应用程序(JAR 和 WAR)将被加载为动态模块并使用依赖关系来访问 JBoss EAP 6 提供的 API。
依赖关系的类型有两种:explicit(显性的)和 implicit(隐性的)
显性依赖关系是由开发人员声明的。静态的模块可以在 modules.xml 文件里声明依赖关系。动态模块可以在 MANIFEST.MF 或 jboss-deployment-structure.xml 里声明依赖关系。
您可以指定显性的依赖关系为可选的。无法加载可选依赖关系不会导致模块无法加载。然而,如果依赖关系以后变成可用时,它将无法添加到模块的 Class path 里。模块加载时依赖关系就必须是可用的。
隐性的依赖关系在某些条件满足或在部署里发现元数据时自动由应用服务器添加。JBoss EAP 6 附带的 Java EE 6 API 是通过检测部署里的隐性依赖关系而添加的模块的示例。
我们可以配置部署排除特定的隐性依赖关系。这是通过 jboss-deployment-structure.xml 部署描述符文件来完成的。这常常发生在当应用程序捆绑某个版本的库文件,而应用服务器将试图将其添加为隐性依赖关系的时候。
模块的 Class path 包含自己的类及其直接的依赖关系。模块无法访问其中一个依赖关系的依赖关系类。然而,模块可以指定导出某个显性的依赖关系。导出的依赖关系将提供给任何依赖于导出它的模块的模块。

例 7.2. 模块依赖关系

模块 A 依赖于模块 B 而模块 B 依赖于模块 C。模块 A 可以访问模块 B 的类,模块 B 可以访问模块 C 的类。模块 A 无法访问模块 C 的类。
  • 模块 A 声明了对模块 C 的显性依赖关系,或者
  • 模块 B 导出它对模块 C 的依赖关系。

7.1.4. 子部署类加载器的隔离

EAR 里的每个子部署都是一个动态模块,它有自己的类加载器。在默认情况下,子部署可以访问其他子部署的资源。
如果子部署不应该访问其他子部署的资源(要求严格的子部署隔离),那么就可以启用隔离。