原文
https://www.baeldung.com/java-headless-mode
引言
这篇文章源自集体看到了Kafka的启动脚本中一个“奇怪”的参数:
-Djava.awt.headless=true
拿去谷歌一下发现网上的形容都大差不差,这里找了baeldung(相似国外的菜鸟教程)中的一篇文章,本文内容来自于英文博客原文。
这篇文章介绍了 -Djava.awt.headless 参数的作用,网上大部分的材料都是说“为了进步计算效率和适配性咱们能够应用这种模式,敞开图形显示等性能能够大大节俭设施的计算能力,而且对一些自身没有相干显示设施的机器也能适配,程序也能够失常运行。”,集体认为这些实践内容不太能了解。
当然也有诸如服务器没有显示屏什么的,你得通知程序一声,你工作的中央没有这些设施这种说法 ,为此找了一篇国外的博客介绍。
如何设置?
设置形式如下:
- 在system property中设置 _java.awt.headless_ 为 _true_。
SpringBoot的源码中能够找到相似的代码:
private void configureHeadlessProperty() { System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless))); }
- 启动脚本中进行设置
-Djava.awt.headless=true
:在Kafka的脚本当中存在相似的启动脚本。
KAFKA_JVM_PERFORMANCE_OPTS="-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+ExplicitGCInvokesConcurrent -XX:MaxInlineLevel=15 -Djava.awt.headless=true"
最初一个参数显示它应用headless模式。
- 在执行命令的时候动静增加
-Djava.awt.headless=true
,这种形式和脚本设置启动的形式相似。
Headless 绕过重量级组件
如果一个带有GUI组件的代码在开和关Headless模式下运行别离会有什么不同的成果?
@Test public void FlexibleApp() { if (GraphicsEnvironment.isHeadless()) { System.out.println("Hello World"); } else { JOptionPane.showMessageDialog(null, " showMessageDialog Hello World"); } }
下面的代码如果敞开了Headless模式,则打印Hello World会变为图形化界面。
如果开启Headless,则会打印在控制台。
Headless Mode 在UI组件的利用案例
Java Headless Mode 的典型案例可能是应用图形转化器,咱们有时候可能须要图形数据进行图像处理,然而不肯定须要理论显示。
上面通过一个单元测试来模仿这些状况:
@Before public void setUpHeadlessMode() { // 通过正文掉上面的代码测试不同的成果 // System.setProperty("java.awt.headless", "true"); } @Test public void whenSetUpSuccessful_thenHeadlessIsTrue() { boolean headless = GraphicsEnvironment.isHeadless(); Assert.assertTrue(headless); }/* 测试通过 正文上面的代码之后,单元测试不通过 // System.setProperty("java.awt.headless", "true"); */
应用awt的组件java.awt.GraphicsEnvironment#isHeadless
,留神较高版本的JDK(例如 JDK11)中awk被间接干掉了,须要下载内部依赖导入才能够应用,倡议抉择JDK8以及以下的版本测试下面的程序。
下面的代码如果正文掉 headless模式,单元测试会间接不通过。上面简略构建了一个图形转化器:
@Test public void whenHeadlessMode_thenImagesWork() { boolean result = false; try (InputStream inStream = HeadlessModeUnitTest.class.getResourceAsStream(IN_FILE); FileOutputStream outStream = new FileOutputStream(OUT_FILE)) { BufferedImage inputImage = ImageIO.read(inStream); result = ImageIO.write(inputImage, FORMAT, outStream); } assertThat(result).isTrue(); }
在接下来的这个例子中,咱们能够看到所有字体的信息,包含字体的度量,也能够让咱们应用。
@Test public void whenHeadless_thenFontsWork() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); String fonts[] = ge.getAvailableFontFamilyNames(); // assertThat(fonts).isNotEmpty(); Font font = new Font(fonts[0], Font.BOLD, 14); FontMetrics fm = (new Canvas()).getFontMetrics(font); // assertThat(fm.getHeight()).isGreaterThan(0); // assertThat(fm.getAscent()).isGreaterThan(0); // assertThat(fm.getDescent()).isGreaterThan(0); }
HeadlessException
有些设施是须要外部设备反对的,否则会抛出上面的异样:
Exception in thread "main" java.awt.HeadlessException at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204) at java.awt.Window.<init>(Window.java:536) at java.awt.Frame.<init>(Frame.java:420)
能够应用Frame来进行验证:
@Test public void whenHeadlessmode_thenFrameThrowsHeadlessException() { Frame frame = new Frame(); frame.setVisible(true); frame.setSize(120, 120); }/* 在开关Headless模式后会有不同的后果 开启:通过 敞开 ava.awt.HeadlessExceptionat java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204) at java.awt.Window.<init>(Window.java:536) at java.awt.Frame.<init>(Frame.java:420) at java.awt.Frame.<init>(Frame.java:385) */
作为一个教训法令,请记住,像Frame和Button这样的顶级组件总是须要一个交互式的环境,并且会抛出这个异样。然而,如果没有明确设置无头模式,它将被抛出,成为一个不可复原的谬误。
总结
通过代码和案例剖析,咱们大抵理解Java Headless Mode模式是怎么一回事,说白了就是屏蔽掉外置设施比方GUI的额定开销,转而用程序本人去进行模仿。
Kafka设置这样的参数就是把性能施展到机制,摈弃所有外部设备烦扰,让服务器尽可能的通过本身程序模仿外部设备。
比方重量级组件控制台打印,在内部设计能够通过JOptionPane
的GUI组件实现可视化成果,而Headless则是利用咱们熟知的System.out
控制台输入输出流实现打印性能的模仿。
以上就是对于 Java Headless Mode 的了解。
程序demo
本文的集体试验代码放到上面局部,文章提到的局部代码可能会无奈编译通过(图形转化器的代码),集体了解代码用意之后就没有深究了,读者碰到报错问题疏忽删除即可。
PS:倡议应用JDK8之前的版本,能够间接引入awt和swing的相干组件。
import jdk.nashorn.internal.ir.LiteralNode; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import static org.junit.Assert.assertThat; public class HandlessTest { @Before public void setUpHeadlessMode() { // 通过正文掉上面的代码测试不同的成果 System.setProperty("java.awt.headless", "true"); } @Test public void whenSetUpSuccessful_thenHeadlessIsTrue() { boolean headless = GraphicsEnvironment.isHeadless(); Assert.assertTrue(headless); }/* 测试通过 正文上面的代码之后,单元测试不通过 // System.setProperty("java.awt.headless", "true"); */ //@Test //public void whenHeadlessMode_thenImagesWork() throws IOException { // boolean result = false; // try (InputStream inStream = HandlessTest.class.getResourceAsStream(IN_FILE); // FileOutputStream outStream = new FileOutputStream(OUT_FILE)) { // BufferedImage inputImage = ImageIO.read(inStream); // result = ImageIO.write(inputImage, FORMAT, outStream); // } // Assert.assertTrue(result); //} // @Test // public void whenHeadlessMode_thenImagesWork() { // boolean result = false; // try (InputStream inStream = HeadlessModeUnitTest.class.getResourceAsStream(IN_FILE); // FileOutputStream outStream = new FileOutputStream(OUT_FILE)) { // BufferedImage inputImage = ImageIO.read(inStream); // result = ImageIO.write(inputImage, FORMAT, outStream); // } // // assertThat(result).isTrue(); // } @Test public void whenHeadless_thenFontsWork() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); String fonts[] = ge.getAvailableFontFamilyNames(); // assertThat(fonts).isNotEmpty(); Font font = new Font(fonts[0], Font.BOLD, 14); FontMetrics fm = (new Canvas()).getFontMetrics(font); // assertThat(fm.getHeight()).isGreaterThan(0); // assertThat(fm.getAscent()).isGreaterThan(0); // assertThat(fm.getDescent()).isGreaterThan(0); } @Test public void whenHeadlessmode_thenFrameThrowsHeadlessException() { Frame frame = new Frame(); frame.setVisible(true); frame.setSize(120, 120); }/* 在开关Headless模式后会有不同的后果 开启:通过 敞开 ava.awt.HeadlessException at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204) at java.awt.Window.<init>(Window.java:536) at java.awt.Frame.<init>(Frame.java:420) at java.awt.Frame.<init>(Frame.java:385) */ @Test public void FlexibleApp() { if (GraphicsEnvironment.isHeadless()) { System.out.println("Hello World"); } else { JOptionPane.showMessageDialog(null, "showMessageDialog Hello World"); } } }
参考资料
https://www.jianshu.com/p/7248b3ff5ca7
https://www.baeldung.com/java-headless-mode](https://www.baeldung.com/java...](https://www.baeldung.com/java...))