ShrinkWrap 是 Java 中最简单的创建归档文件的方法,它为 Arquillian 部署机制提供了动力。本教程作为一个快速课程会教你创建这些代表部署的对象。包括:
- 相对传统的基于文件的归档方式,ShrinkWrap 的目的和好处
- 从头创建一个新的归档文件
- 不同的添加内容的机制
- 从现有的文件结构导入归档
声明
最初,ShrinkWrap 的诞生是出于更简单了测试 Java 企业部署的需要。传统的基于普通文件归档源于 ZIP 标准,这样必需引入一些构建步骤,对所有应用资源进行打包。 一次构建过程要花费不少时间:
$ mvn clean install
... terrifying output trace ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:13.492s
[INFO] ------------------------------------------------------------------------
但作为开发人员,我们使用的是编码环境。基于这种想法去运行一次构建实在是浪费。
所以我们不禁要问: “如果在 Java 中我们能够声明一个对象代表归档,结果会有什么不同?"
结果是一个 Java API 模拟 “jar” 工具,一种具有直观语法的虚拟文件系统。
JavaArchive archive = ShrinkWrap.create(JavaArchive.class,"myarchive.jar")
.addClasses(MyClass.class, MyOtherClass.class)
.addResource("mystuff.properties");
结果是利用 IDE 增量编译的特性,允许我们跳过构建过程。
结果是一种从 IDE 中直接运行测试的方法。
结果是 ShrinkWrap 诞生了。
入门
第一步是让你了解一下 ShrinkWrap 体系结构,核心由三部分组成:
Name | Maven Coordinates |
---|---|
API | org.jboss.shrinkwrap:shrinkwrap-api |
SPI | org.jboss.shrinkwrap:shrinkwrap-spi |
Implementation | org.jboss.shrinkwrap:shrinkwrap-impl-base |
只有 API 是必须包含在编译的 Classpath 中, SPI 和 Implementation 仅在运行时需要。这样可以很好的将直接使用和项目内部类进行了分离。
在 Maven 中, 利用传递性依赖的 POM, 这些依赖可以放在不同的 Scope 中,从 Maven Central 资源库获取:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- snip -->
<dependency> <groupId>org.jboss.shrinkwrap</groupId> <artifactId>shrinkwrap-depchain</artifactId> <version>${version.shrinkwrap}</version> <type>pom</type> </dependency>
<!-- snip --> </project>
为了顾及那些还没有使用 Maven 资源库系统的项目,ShrinkWrap 发布包将所有的模块放在一个下载文件中,你可以根据自己的需要手动设置依赖。
前提条件
- JRE5+ 运行环境
- 无需额外的依赖
ShrinkWrap 可以运行任何 Java 5 或者更高的运行环境,但是编译时最少需要 JDK6。
API 文档
每个发布版本的 JavaDoc 在 这里 。
开放编码
Fork 我们,并参与 开发 。
归档文件的创建
ShrinkWrap 库的主要入口是 org.jboss.shrinkwrap.api.ShrinkWrap
类。你可以调用 create
方法来创建一个新的 Archive
, 虚拟文件系统的通用视图允许添加名为 Asset
的内容到一个位置,称之为 ArchivePath
。下表显示了更多 ShrinkWrap 名称中的通用术语。
Common Term | ShrinkWrap Class | Description |
---|---|---|
Archive | org.jboss.shrinkwrap.api.Archive |
A collection of resources, essentially a virtual filesystem |
File | org.jboss.shrinkwrap.api.Node |
An entry in an Archive ; may represent content or a directory |
Path | org.jboss.shrinkwrap.api.ArchivePath |
Location in an Archive under which a Node lives |
Asset | org.jboss.shrinkwrap.api.Asset |
Byte-based content within a Node |
另外, Archive
包括多个视图,通常情况下,你不会直接处理 Archive
类。相反,ShrinkWrap 提供了一些 Archive
扩展,自带了一些辅助方法来操作类型相关的内容。
Archive Type | Description |
---|---|
org.jboss.shrinkwrap.api.GenericArchive |
Simplest type of concrete user-view of an Archive ; supports generic operations |
org.jboss.shrinkwrap.api.spec.JavaArchive |
JAR type; allows addition of Class es, Package s, and Manifest operations |
org.jboss.shrinkwrap.api.spec.EnterpriseArchive |
Java EE EAR type; supports Manifest and related spec operations |
org.jboss.shrinkwrap.api.spec.WebArchive |
Java EE WAR type; supports operations common to web application deployments |
org.jboss.shrinkwrap.api.spec.ResourceAdaptorArchive |
Java EE RAR type; supports operations common to resource adaptor deployments |
要创建一个 Archive
, 很简单, 只要选择你要创建的归档类型,根据需要,还可以添加一个名称到 ShrinkWrap:create
静态方法中:
GenericArchive myArchive = ShrinkWrap.create(GenericArchive.class,"myArchive.jar");
就这样,你创建了第一个 ShrinkWrap 归档文档!
添加内容
当然一个代表空归档的对象是毫无意义的。所以我们试着看添加一些内容。正如前面所说的那样,内容由 Asset
进行构造,所以我们先看 ShrinkWrap 提供的一些 Asset
实现:
Asset | Represents |
---|---|
org.jboss.shrinkwrap.api.asset.ArchiveAsset |
Nested Archive content |
org.jboss.shrinkwrap.api.asset.ByteArrayAsset |
byte[] or InputStream content |
org.jboss.shrinkwrap.api.asset.ClassAsset |
Java Class content |
org.jboss.shrinkwrap.api.asset.ClassLoaderAsset |
A resource which can be loaded by an optionally-specified ClassLoader |
org.jboss.shrinkwrap.api.asset.FileAsset |
File content |
org.jboss.shrinkwrap.api.asset.StringAsset |
String content |
org.jboss.shrinkwrap.api.asset.UrlAsset |
Content located at a given URL |
org.jboss.shrinkwrap.api.asset.EmptyAsset |
Empty (0-byte) content |
另外,因为 Asset
是一个接口,你可以提供你自己的实现,来处理任何代表 InputStream
基于字节流的内容。例如,下面的代码片断演示如何将一个 Activation Framework DataSource
转换成 Asset
:
final DataSource dataSource = null; // Assume you have this
Asset asset = new Asset() {
@Override
public InputStream openStream() {
try {
return dataSource.getInputStream();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
};
Archive:add
方法允许我们传入一些 Asset
内容,并加入到 ArchivePath
下面。
myArchive.add(myAsset,"path/to/content");
System.out.println(myArchive.toString(true));
传递一个 true
标志给 Archive
的 toString
方法来递归打印 "ls -l"
样式的输出:
myArchive.jar:
/path/
/path/to/
/path/to/content
根据你要操作的不同内容的类型, 我们先前提到的 Archive
视图非常有用。例如,一个标准的 JAR 文件一般包含 .class
文件和其它资源,所以你可以用 JavaArchive
类型来添加这些内容。
ShrinkWrap 支持一种简单的机制,允许你的归档文件在不同的视图间切换, 由 org.jboss.shrinkwrap.api.Assignable
接口的 as
方法提供,每种视图都是从 Assignable
继承。所以要让你的归档用上 JavaArchive
视图,要添加 Class
资源, 代码可以简化为:
myArchive.as(JavaArchive.class).addClasses(String.class, Integer.class);
System.out.println(myArchive.toString(true));
archive.jar:
/java/
/java/lang/
/java/lang/String.class
/java/lang/Integer.class
使用这种机制的好处是保持 ShrinkWrap 用法简洁和直观,同时提供了多重继承语言的灵活性。
操作文件内容
因为 ShrinkWrap 扎根于 Java EE 并与 Arquillian 测试平台密不可分,但不局限这些领域。事实上,ShrinkWrap 更偏向扮演一个归档文件的虚拟系统的角色。因此,它提供了一种简单机制来操作普通文件结构。
从上面的代码可以看出,也许我们想用 ShrinkWrap 对包中所有的 .class
文件进行打包,并输出到一个标准的 JAR 或者 ZIP 格式。代码很简单:
JavaArchive archive = ShrinkWrap.create(JavaArchive.class,
"myPackage.jar").addPackage(this.getClass().getPackage());
System.out.println(archive.toString(true));
archive.as(ZipExporter.class).exportTo(
new File("/home/alr/Desktop/myPackage.jar"), true);
javalang.jar:
/org/
/org/alr/
/org/alr/test/
/org/alr/test/TestClass.class
简单的分析一下。首先,我们创建了一个 JavaArchive
,加入当前的 Class
所在 Package
的所有内容。为了验证包含了哪些内容,然后我们将它输出到控制台。最后一行,我们再次利用 JavaArchive
中从 Assignable
派生的特性切换到新视图:输出为 ZIP 格式。本例中,我们使用相应的 ZipExporter
,允许输出到一个 File
, OutputStream
, 甚至将内容转化为 InputStream
,这样我们还可以进行字节流操作。
ShrinkWrap 自带三种 exporters:
Exporter | Output Format |
---|---|
org.jboss.shrinkwrap.api.exporter.TarExporter |
TAR |
org.jboss.shrinkwrap.api.exporter.TarGzExporter |
TAR.GZ |
org.jboss.shrinkwrap.api.exporter.ZipExporter |
ZIP |
当然,我们也可以依葫芦画瓢使用下面标准的 importers 之一从普通文件来创建一个 ShrinkWrap 归档:
Importer | Output Format |
---|---|
org.jboss.shrinkwrap.api.importer.TarImporter |
TAR |
org.jboss.shrinkwrap.api.importer.TarGzImporter |
TAR.GZ |
org.jboss.shrinkwrap.api.importer.ZipImporter |
ZIP |
前面代码改成使用导入的方法可能看起来像这样:
JavaArchive roundtrip = ShrinkWrap
.create(ZipImporter.class, "myPackageRoundtrip.jar")
.importFrom(new File("/home/alr/Desktop/myPackage.jar"))
.as(JavaArchive.class);
注意我们是如何将 ZipImporter
传递给 ShrinkWrap.create
方法的,它也是一个 Assignable
! 开始注意到这个把戏了吗?
这里我们简短的介绍了如何 ShrinkWrap 操作归档文件内容。 我们希望你能够深入研究 API,它更直观,更一致,欢迎到我们社区。
Share the Knowledge
Find this guide useful?
There’s a lot more about Arquillian to cover. If you’re ready to learn more, check out the other available guides.
Feedback
Find a bug in the guide? Something missing? You can fix it by forking this website, making the correction and sending a pull request. If you’re just plain stuck, feel free to ask a question in the user discussion forum.
Recent Changelog
- Sep 21, 2017: Fix(scripts) timeout for waiting for timestamp available on pages is by Matous Jobanek