由于需要包含JRE,因此Java映像通常很大。在Java 9中,我们可以创建一个仅包含应用程序所需类的自定义JRE。
通常,拥有一个小型Docker映像被认为是一种很好的做法。尽管我们可以减小操作系统基本映像的大小,例如Alpine Linux仅5 MB,但在Java 9之前,我们无法对JRE进行任何处理。最轻的是阿尔卑斯JRE(openjdk:8-jre-alpine),大约107MB。这是因为我们包含了与应用程序无关的类,例如applet或awt类,即使您的应用程序没有头也是如此。
从Java 9开始,JRE被分解为模块,因此可以只包含应用程序使用的模块。Java 9的jLink使我们能够创建一个定制的“足够”的JRE,该JRE仅由应用程序类及其依赖的模块组成。
在本文中,我们将看到如何对使用jLink构建的Java应用程序进行泊坞处理。我们将使用Maven在Eclipse中构建一个正在运行的示例。在此过程中,我们将提供有关如何在Eclipse中构建模块化Java应用程序的详细信息。我将假定您具有比Oxygen更高的Eclipse版本,并且可以在Java或更高版本的Java 9上运行。
首先,使用快速入门原型创建一个Maven项目,并为其提供GAV(com.tn.jlink; example)。创建一个包com.tn.jlink.example。右键单击项目,然后选择配置->创建 module-info.java并调用模块com.tn.jlink。(有关命名模块的最佳做法,请参见此内容)。Eclipse创建文件,并且它已经包含“ exports com.tn.jlink.example”。在其上添加“ requires java.logging”。
模块 com。tn。jlink {
出口 com。tn。JLINK。例子;
需要 java。测井;
}
为了简单起见,我们将仅使用内置的Java模块
在该程序包中,创建此类:
包 com。tn。JLINK。例子;
/ **
* 你好,世界!
*
导入java.util.logging.Logger;
公共类HelloWorld
{
私有静态最终Logger LOG = Logger.getLogger(HelloWorld.class.getName());
公共静态void main(String [] args)
{
LOG.info(“ Hello World!”);
}
}
现在,通过在后面添加此部分来修改pom <dependencies>
。
<构建>
<插件>
<插件>
< groupId > org.apache.maven.plugins </ groupId >
< artifactId > maven-compiler-plugin </ artifactId >
<版本> 3.8.0 </版本>
<配置>
<版本> 11 </版本>
</配置>
</插件>
</插件>
</ build >
请注意,对于Java 9及更高版本的应用程序,编译器插件必须为3.8或更高版本。
您可以通过构建它来检查它(Run-> Run as…,Maven Build)。对于目标,输入clean install,在目标目录下,您将找到example-0.0.1-SNAPSHOT.jar文件。
到此结束有关如何将模块化Java项目构建为模块化JAR的介绍。现在我们来使用jLink进行编译。运行jLink的命令行语法为:
jlink [选项] –module-path modulepath
–add-modules模块[,模块…]
--output <目标目录>
但是,距离任何人使用命令行来构建Java项目已经有好几年了。此外,Windows中的命令行很烂。相反,我们将为Maven使用ModiTect插件。它支持Java模块系统的许多目标,其中一个是我们感兴趣的目标,即创建自定义运行时映像。现在将以下内容添加到pom中
<插件>
< groupId > org.moditect </ groupId >
< artifactId > moditect-maven-plugin </ artifactId >
<版本> 1.0.0.Beta2 </版本>
<处决>
<执行>
< id >创建运行时图像</ id >
<阶段>包</阶段>
<目标>
<目标>创建运行时图像</目标>
</目标>
<配置>
< modulePath >
<路径>
$ {project.build.directory} / $ {project.artifactId}-$ {project.version}。$ {project.packaging}
</ path >
</ modulePath >
<模块>
<模块> com.tn.jlink </模块>
</模块>
<启动器>
<名称>您好</名称>
<模块>
com.tn.jlink / com.tn.jlink.example.HelloWorld
</模块>
</启动器>
< outputDirectory >
$ {project.build.directory} / jlink-image
</ outputDirectory >
< stripdebug >是</ stripdebug >
< noManPages >是</ noManPages >
< noHeaderFiles >是</ noHeaderFiles >
</配置>
</执行>
</死刑>
</插件>
元素的简要说明:
modulePath
:是包含模块的目录的路径。对于我们来说,我们只是将我们刚刚构建的JAR文件放在此路径上。请注意,java.logging模块是隐式包含的Java模块。我们通过使用Java模块作了一些欺骗。大多数模块都在外部JAR文件中,并且为了使该元素简单,我们应该将JAR放在子目录中,并将其 放在模块路径中。- 模块/模块:我们只包括创建模块信息时输入的名称。我们以给定的名称列出模块,每个模块元素一个。
outputDirectory
:应在其中创建运行时映像的目录- 启动器:jLink可以创建Shell脚本来启动主类。在这里,我们给出文件名。我们称它为“你好”。
- 启动器/模块:这有点令人困惑。如果您做的不正确,则会收到未指定主类的错误。这是我们要启动的类的全限定名,即moduleName /全限定类名。
stripDebug
:是否去除调试符号。这是一个jLink命令行选项。我们将其设置为true以减小图像的大小noManPages
,noHeaderFiles
:与上面相同。
现在,如果我们构建它,您将找到一个新的目标子目录,名为jlink-image。在bin目录中查找。其中包含启动脚本“ hello”和“ hello.bat”。运行它来查看:
INFO:世界你好 !
现在我们进入将其填充到Docker映像中的最后一步。作为Java开发人员,我们习惯于与平台无关。但是jLink映像取决于构建它的平台。回想一下,Docker运行着一个小的内存Linux内核。如果我们以此为依据,则Windows将无法运行。因此,我们需要在Linux上构建映像。由于我们希望使图像保持较小,因此作为基本图像,我们将使用5MB以下的高山图像。
现在,我们遇到了另一个问题。高山发行版使用musl代替其他Linux发行版使用的libgc。它们都是Linux内核上的C ++ API。针对glibc编译的C或C ++代码将无法在Musl系统上运行,反之亦然。JVM是用C ++编写的(至少现在是这样)。底线是我们必须在Alpine上构建它。如果您在Docker Hub中查看Maven发行版,则只有Java 12高山发行版,这就是我们将要使用的发行版。最后,这是Dockerfile(我们将在Eclipse项目下创建)
来自maven:3.6-jdk-12-alpine作为构建
WORKDIR / wrk
复制pom.xml。
复制src src
运行MVN全新安装
来自高山:3.8
复制--from = build / wrk / target / jlink-image / app
ENTRYPOINT [“ / app / bin / hello”]
现在,构建图像并将其称为“示例”。
docker image build -t示例
并运行它
docker容器运行-ti示例
并看到INFO:Hello World
。运行docker images
命令以查看大小:
REPOSITORY TAG 图像 ID CREATED SIZE
示例 最新的 89e421476953 47 小时 前 54 MB
通常,Java Hello World映像的大小在120 MB以北。使用jLink会产生明显较小的图像。
我们谨此告诫。图像大小不是全部。图像一次下载,缓存并在许多应用程序中使用。但是,jLink映像特定于应用程序,并且不可重用。因此,您的行驶里程会根据您要执行的操作而有所不同。 福州软件开发