WildFly应用程序服务器附带一个补丁机制,这使得升级服务器现有模块或添加新模块变得非常容易。例如,Hibernate Validator提供补丁文件,可让您将WildFly 10.1升级到Bean Validation 2.0的预览版本。
但您也可以使用补丁机制将您自己的自定义库添加到WildFly中,使其可供部署的应用程序使用。即使您只将单个应用程序部署到一个WildFly实例,这也可以非常有用,因为它可以减小您的部署单元(WAR等)的大小,从而加快构建和部署时间。
但是WildFly补丁是如何创建的呢?补丁文件通常是包含要添加或更新的模块(以及一些额外的元数据)的ZIP文件。因此,从理论上讲,您可以通过手工创建它们,但有一个patch-gen工具可以极大地简化这项任务。
以下我们将一步一步地描述如何使用patch-gen-maven-plugin创建一个WildFly补丁。作为一个例子,我们将生成一个补丁文件,将该Eclipse Collections库添加到WildFly实例中。
模块描述符
我们首先需要的是JBoss Modules系统的模块描述符,这是WildFly的底层基础。Eclipse Collections分为两个JAR,一个用于API,一个用于实现。因此,我们将创建以下两个描述符
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.3" name="org.eclipse.collections.api">
<resources>
<resource-root path="eclipse-collections-api-${eclipse.collections.version}.jar" />
</resources>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.3" name="org.eclipse.collections">
<resources>
<resource-root path="eclipse-collections-${eclipse.collections.version}.jar" />
</resources>
<dependencies>
<module name="org.eclipse.collections.api" />
</dependencies>
</module>
每个描述符指定了对应JAR的资源(版本属性占位符使用Maven资源过滤进行替换)。实现模块还声明了对API模块的依赖。
补丁工具配置文件
《patch-gen》工具需要一个小的配置文件,用于描述一些补丁元数据(例如,补丁应用的服务器版本和补丁类型——一次性或累积型)以及修复的模块。
<?xml version='1.0' encoding='UTF-8'?>
<patch-config xmlns="urn:jboss:patch-config:1.0">
<name>wildfly-${wildfly.version}-eclipse-collections-${eclipse.collections.version}</name>
<description>This patch adds Eclipse Collections ${eclipse.collections.version} to a WildFly ${wildfly.version} installation</description>
<element patch-id="layer-base-wildfly-${wildfly.version}-eclipse-collections-${eclipse.collections.version}">
<one-off name="base" />
<description>This patch adds Eclipse Collections ${eclipse.collections.version} to a WildFly ${wildfly.version} installation</description>
<specified-content>
<modules>
<added name="org.eclipse.collections.api" />
<added name="org.eclipse.collections" />
</modules>
</specified-content>
</element>
<specified-content/>
</patch-config>
准备补丁创建
《patch-gen》工具需要两个要修复的发行版的目录作为输入:一个包含原始、未修复的WildFly结构的目录,另一个包含原始WildFly结构以及添加(或更新)的模块的目录。我们可以使用Maven依赖插件通过两次提取WildFly发行版来创建这两个目录。
...
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-wildfly</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-dist</artifactId>
<version>${wildfly.version}</version>
<type>tar.gz</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/wildfly-original</outputDirectory>
</artifactItem>
<artifactItem>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-dist</artifactId>
<version>${wildfly.version}</version>
<type>tar.gz</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/wildfly-patched</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
...
现在我们需要将Eclipse Collections JAR文件添加到第二个目录中。让我们为这一步配置Maven依赖插件的另一个执行。
...
<execution>
<id>add-eclipse-collections</id>
<phase>prepare-package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections-api</artifactId>
<version>${eclipse.collections.version}</version>
<overWrite>false</overWrite>
<outputDirectory>${wildflyPatched}/modules/system/layers/base/org/eclipse/collections/api/main</outputDirectory>
</artifactItem>
<artifactItem>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>${eclipse.collections.version}</version>
<overWrite>false</overWrite>
<outputDirectory>${wildflyPatched}/modules/system/layers/base/org/eclipse/collections/main</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
...
我们还需要添加module.xml描述符,以便它们位于相应的JAR文件旁边。Maven资源插件有助于完成这项工作。它还可以用于替换patch.xml描述符中的占位符。以下两个插件执行是必需的
...
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-module-descriptors</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${wildflyPatched}/modules</outputDirectory>
<resources>
<resource>
<directory>src/main/modules</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>filter-patch-descriptor</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/</outputDirectory>
<resources>
<resource>
<directory>src/main/patch</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
...
配置Patch-Gen Maven插件
在所有这些准备工作完成之后,我们现在需要配置patch-gen Maven插件,该插件最终将组装补丁文件。
...
<plugin>
<groupId>org.jboss.as</groupId>
<artifactId>patch-gen-maven-plugin</artifactId>
<executions>
<execution>
<id>create-patch-file</id>
<phase>prepare-package</phase>
<goals>
<goal>generate-patch</goal>
</goals>
<configuration>
<appliesToDist>${wildflyOriginal}</appliesToDist>
<updatedDist>${wildflyPatched}</updatedDist>
<patchConfig>${project.build.directory}/patch.xml</patchConfig>
<outputFile>${patchFile}</outputFile>
</configuration>
</execution>
</executions>
</plugin>
...
插件需要以下配置
-
未修复WildFly目录的路径
-
已修复WildFly目录的路径
-
patch.xml描述符的路径
-
补丁文件的输出路径
最后一步,我们需要确保创建的补丁文件被添加到Maven构建中。这样,创建的ZIP文件可以被安装到本地Maven仓库并部署到Nexus等仓库服务器。构建辅助Maven插件有助于完成最后这项任务
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>attach-patch-artifact</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${patchFile}</file>
<type>zip</type>
<classifier>wildfly-${wildfly.version}-patch</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
...
运行构建
在完成所有配置后,可以通过运行mvn clean install
来构建补丁文件。创建的补丁文件应该具有以下结构
├── META-INF
├── README.txt
├── layer-base-wildfly-10.1.0.Final-eclipse-collections-8.1.0
│ └── modules
│ └── org
│ └── eclipse
│ └── collections
│ ├── api
│ │ └── main
│ │ ├── eclipse-collections-api-8.1.0.jar
│ │ └── module.xml
│ └── main
│ ├── eclipse-collections-8.1.0.jar
│ └── module.xml
├── misc
└── patch.xml
正如我们预期的那样,补丁包含Eclipse Collections JAR文件以及相应的module.xml描述符。patch.xml描述符包含补丁基础设施的元数据,例如,此补丁可以应用的WildFly版本以及添加的模块的哈希校验和。
应用和使用补丁
一旦创建了补丁,我们可以使用随WildFly一起提供的jboss-cli工具来应用它。
<JBOSS_HOME>/bin/jboss-cli.sh "patch apply --path path/to/eclipse-collections-8.1.0-wildfly-10.1.0.Final-patch.zip"
如果补丁已成功应用,您应该看到以下输出
{
"outcome" : "success",
"result" : {}
}
然后您就可以在您的部署应用程序中使用Eclipse Collections API。只需确保将两个新模块暴露给您的应用程序。为此,请将一个名为META-INF/jboss-deployment-structure.xml的描述符添加到您的部署单元中
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure
xmlns="urn:jboss:deployment-structure:1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<deployment>
<dependencies>
<module name="org.eclipse.collections.api" />
<module name="org.eclipse.collections" />
</dependencies>
</deployment>
</jboss-deployment-structure>
如果您想尝试创建自己的WildFly补丁,请查看GitHub上的此示例项目。它包含创建Eclipse Collections补丁的完整pom.xml。还有一个集成测试模块,该模块接收补丁文件,将其应用到WildFly实例上,并运行一个小的测试(使用Arquillian),在服务器上调用Eclipse Collections API。
如果您对这篇博客文章有任何反馈或想分享您对WildFly修复基础设施的经验,请在我们下面的评论中告诉我们。