原文https://www.baeldung.com/java-headless-mode简介本文源于Kafka启动脚本中的一个“奇怪”参数:-Djava。awt.headless=true去谷歌一下,发现网上的描述还不错。这里找了baeldung的一篇文章(类似国外菜鸟教程)。本文内容来自英文原版博客。本文介绍-Djava.awt.headless参数的作用。网上的资料大多是说“为了提高计算效率和适应性,我们可以使用这种模式。关闭图形显示等功能可以大大节省设备的计算能力,而且还可以适配对于一些没有相关显示设备的机器,程序也可以正常运行。”个人觉得这些理论内容不是很懂。当然也有服务器没有显示屏之类的,你要告诉程序你工作的地方没有这个设备,所以找了一篇国外的博客介绍。如何设置?设置方法如下:在系统属性中将_java.awt.headless_设置为_true_。在SpringBoot的源码中可以找到类似的代码:));}在启动脚本中设置-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模式和headless模式下,会有什么不同的效果?@TestpublicvoidFlexibleApp(){if(GraphicsEnvironment.isHeadless()){System.out.println("HelloWorld");}else{JOptionPane.showMessageDialog(null,"showMessageDialogHelloWorld");}}上面的代码如果关闭Headless模式,打印HelloWorld会变成图形界面。如果启用了Headless,它将打印在控制台上。HeadlessMode在UI组件中的应用JavaHeadlessMode的一个典型案例可能是使用图形转换器。有时我们可能需要图形数据来进行图像处理,但不一定是为了实际显示。让我们通过单元测试来模拟这些情况:@BeforepublicvoidsetUpHeadlessMode(){//通过注释掉下面的代码来测试不同的效果//System.setProperty("java.awt.headless","true");}@TestpublicvoidwhenSetUpSuccessful_thenHeadlessIsTrue(){booleanheadless=GraphicsEnvironment.isHeadless();Assert.assertTrue(无头);}/*下面代码测试通过后,单元测试失败//System.setProperty("java.awt.headless","true");*/使用awt组件java.awt.GraphicsEnvironment#isHeadless,注意awk在JDK高版本(如JDK11)中被直接杀掉,需要下载导入外部依赖后才能使用。建议选择JDK8及以下版本测试以上程序。如果上面的代码注释掉headless模式,单元测试会直接失败。图形转换器的简单构建如下:@TestpublicvoidwhenHeadlessMode_thenImagesWork(){booleanresult=false;尝试(InputStreaminStream=HeadlessModeUnitTest.class.getResourceAsStream(IN_FILE);FileOutputStreamoutStream=newFileOutputStream(OUT_FILE)){BufferedImageinputImage=.read(inStream);结果=ImageIO.write(inputImage,FORMAT,outStream);}assertThat(result).isTrue();在下面的例子中,我们可以看到所有的字体信息,包括fontMetrics也可以供我们使用。@TestpublicvoidwhenHeadless_thenFontsWork(){GraphicsEnvironmentge=GraphicsEnvironment.getLocalGraphicsEnvironment();字符串字体[]=ge.getAvailableFontFamilyNames();//assertThat(字体).isNotEmpty();Fontfont=newFont(fonts[0],Font.BOLD,14);FontMetricsfm=(newCanvas()).getFontMetrics(字体);//assertThat(fm.getHeight()).isGreaterThan(0);//assertThat(fm.getAscent()).isGreaterThan(0);//assertThat(fm.getDescent()).isGreaterThan(0);}HeadlessException有些设备需要外部设备支持,否则会抛出以下异常:Exceptioninthread"main"java.awt.HeadlessExceptionatjava.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)atjava.awt.Window。(Window.java:536)atjava.awt.Frame.(Frame.java:420)可以使用Frame进行验证:@TestpublicvoidwhenHeadlessmode_thenFrameThrowsHeadlessException(){Frameframe=newFrame();frame.setVisible(true);frame.setSize(120,120);}/*开启Headless模式后会有不同的结果:通过在java.awt.Window.(Window.java:536)atjava.awt.Frame.(Frame.java:420)atjava.awt.Frame.(Frame.java:385)*/根据经验,请记住顶部-像Frame和Button这样的层次组件总是需要一个交互环境,并且会抛出这个异常。但是,如果没有显式设置无头模式,它将作为不可恢复的错误抛出。总结通过代码和案例分析,我们对JavaHeadlessMode到底是什么有了一个大概的了解。说白了就是屏蔽GUI等外部设备的额外开销,用程序自己模拟。在Kafka中设置这样的参数是为了最大化机制的性能,丢弃所有外部设备的干扰,尽可能让服务器通过自己的程序来模拟外部设备。例如重量级组件的控制台打印可以在外部设计中通过JOptionPane的GUI组件进行可视化,而Headless则是使用大家熟知的System.out控制台输入输出流来完成打印功能的模拟。以上就是对JavaHeadlessMode的理解。程序demo本文个人实验代码放在下面部分。文中提到的部分代码可能无法通过编译(图形转换器的代码)。明白代码意图后,就不深究了。读者遇到错误忽略删除。.PS:推荐使用JDK8之前的版本,可以直接引入awt和swing的相关组件。导入jdk.nashorn.internal.ir.LiteralNode;导入org.junit.Assert;导入org.junit.Before;导入org.junit.Test;导入javax.imageio.ImageIO;导入javax.swing.*;导入java.awt.*;导入java.awt.image.BufferedImage;导入java.io.FileOutputStream;导入java.io.IOException;导入java.io.InputStream;导入静态org.junit.Assert.assertThat;publicclassHandlessTest{@BeforepublicvoidsetUpHeadlessMode(){//通过注释掉以下代码来测试不同的效果System.setProperty("java.awt.headless","true");}@TestpublicvoidwhenSetUpSuccessful_thenHeadlessIsTrue(){booleanheadless=GraphicsEnvironment.isHeadless();Assert.assertTrue(无头);}/*测试通过后,注释以下代码后单元测试失败//System.setProperty("java.awt.headless","true");*///@Test//publicvoidwhenHeadlessMode_thenImagesWork()抛出IOException{//布尔结果=false;//try(InputStreaminStream=HandlessTest.class.getResourceAsStream(IN_FILE);//FileOutputStreamoutStream=newFileOutputStream(OUT_FILE)){//BufferedImageinputImage=ImageIO.read(inStream);//结果=ImageIO.write(inputImage,FORMAT,outStream);//}//断言.assertTrue(结果);//}//@Test//publicvoidwhenHeadlessMode_thenImagesWork(){//布尔结果=false;//try(InputStreaminStream=HeadlessModeUnitTest.class.getResourceAsStream(IN_FILE);//FileOutputStreamoutStream=newFileOutputStream(OUT_FILE)){//BufferedImageinputImage=ImageIO.read(inStream);//结果=ImageIO.write(inputImage,FORMAT,outStream);//}////assertThat(result).isTrue();//}@TestpublicvoidwhenHeadless_thenFontsWork(){GraphicsEnvironmentge=GraphicsEnvironment.getLocalGraphicsEnvironment();字符串字体[]=ge.getAvailableFontFamilyNames();//assertThat(字体).isNotEmpty();Fontfont=newFont(fonts[0],Font.BOLD,14);FontMetricsfm=(newCanvas()).getFontMetrics(字体);//assertThat(fm.getHeight()).isGreaterThan(0);//assertThat(fm.getAscent()).isGreaterThan(0);//assertThat(fm.getDescent()).isGreaterThan(0);}@TestpublicvoidwhenHeadlessmode_thenFrameThrowsHeadlessException(){Frameframe=newFrame();frame.setVisible(true);frame.setSize(120,120);}/*onswitch开启Headless模式后,会有不同的结果:通过关闭ava.awt.HeadlessExceptionatjava.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)atjava.awt.Window.(Window.java:536)在java.awt.Frame.(Frame.java:420)在java.awt.Frame.>(Frame.java:385)*/@TestpublicvoidFlexibleApp(){if(GraphicsEnvironment.isHeadless()){System.out.println("HelloWorld");}else{JOptionPane.showMessageDialog(null,"showMessageDialogHelloWorld");}}}参考资料https://www.jianshu.com/p/7248b3ff5ca7https://www.baeldung.com/java-headless-mode](https://www.baeldung.com/java...](https://www.baeldung.com/java...))