Java 的 java.awt.headless 模式

本文将简单介绍 java 的 java.awt.headless 模式

什么是 java.awt.headless?

Headless 模式是系统的一种配置模式。在系统可能缺少显示设备、键盘或鼠标这些输入输出外设的情况下可以使用该模式。

何时使用 headless mode?

Headless 模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。

想想你的应用不停的生成一张图片,比如,当用户每次登陆系统是都要生成一张认证图片。当创建图片时,你的应用既不需要显示器也不需要键盘。让我们假设一下,现在你的应用有个主架构或者专有服务器,但这个服务没有显示器,键盘或者鼠标。理想的决定是用环境的大量视觉计算能力而不是非视觉特性。在Headless模式下生成的图片可以传递到Headful系统进行更深层次渲染。

在 java.awt.toolkit 和 java.awt.graphicsenvironment 类中有许多方法,除了对字体,图像和打印的操作外还有调用显示器,键盘和鼠标的方法。但是有一些类中,比如 Canvas 和 Panel,可以在 headless 模式下执行。在 J2SE 1.4 平台之后就提供了对 Headless 模式的支持。

如何使用 Headless mode?

一般是在程序开始激活 headless 模式,告诉程序,现在你要工作在 Headless 模式下,就不要指望硬件帮忙了,你得自力更生,依靠系统的计算能力模拟出这些特性来。

你可以通过下面代码开启 Headless 模式:

System.setProperty("java.awt.headless", "true");

Headless mode简单实例

(1)实例中用到的图片,名称为“mysql_cluster.png”。将该图片放到项目的 resources 目录。

Java 的 java.awt.headless 模式

(2)实例 Java 代码:

import java.awt.*;
import java.io.*;
import java.awt.print.*;
import java.net.URL;
import javax.imageio.*;

/**
 * 简单实用 java 的 Headless 模式
 *
 * @author Administrator
 * @date 2021/3/6 22:16
 */
public class HeadlessBasics {

    public static void main(String[] args) {
        // Set system property.
        // Call this BEFORE the toolkit has been initialized, that is,
        // before Toolkit.getDefaultToolkit() has been called.
        System.setProperty("java.awt.headless", "true");

        // 下面的这段代码展示了如果使用 Toolkit类的beep方法发出嘟嘟声
        // This triggers creation of the toolkit.
        // Because java.awt.headless property is set to true, this
        // will be an instance of headless toolkit.
        Toolkit tk = Toolkit.getDefaultToolkit();
        // Standard beep is available.
        tk.beep();

        // Check whether the application is
        // running in headless mode.
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        System.out.println("Headless mode: " + ge.isHeadless());

        // No top levels are allowed.
        boolean created = false;
        try {
            Frame f = new Frame("Frame");
            created = true;
        } catch (Exception z) {
            z.printStackTrace(System.err);
            created = false;
        }
        System.err.println("Frame is created: " + created);

        // No other components except Canvas and Panel are allowed.
        created = false;
        try {
            Button b = new Button("Button");
            created = true;
        } catch (Exception z) {
            z.printStackTrace(System.err);
            created = false;
        }
        System.err.println("Button is created: " + created);

        // Canvases can be created.
        final Canvas c = new Canvas() {
            public void paint(Graphics g) {
                Rectangle r = getBounds();
                g.drawLine(0, 0, r.width - 1, r.height - 1);
                // Colors work too.
                // 这段代码显示了如何使用指定的红,绿,蓝的值来设置一条线的颜色。Graphics对象是用来绘制这条线的
                g.setColor(new Color(255, 127, 0));
                g.drawLine(0, r.height - 1, r.width - 1, 0);
                // And fonts
                // 这段代码显示了怎么使用Font类画一个文本字符串并设置文字的字体。Graphics对象是用来绘制这个字符串的
                g.setFont(new Font("Arial", Font.ITALIC, 12));
                g.drawString("Test", 32, 8);
            }
        };
        // And all the operations work correctly.
        c.setBounds(32, 32, 128, 128);

        // Images are available.
        // 下面的代码中,javax.imageio.ImageIO类的使用read()方法对 mysql_cluster.png 图片进行解码,并返回一个缓存图片
        Image i = null;
        try {
            URL url = HeadlessBasics.class.getResource("/mysql_cluster.png");
            File f = new File(url.getFile());
            i = ImageIO.read(f);
        } catch (Exception z) {
            z.printStackTrace(System.err);
        }
        final Image im = i;

        // Print system is available.
        // 这段代码演示了如何打印已经准备好的画布,你可以使用paint方法自定义打印机的的默认画面
        PrinterJob pj = PrinterJob.getPrinterJob();
        pj.setPrintable(new Printable() {
            public int print(Graphics g, PageFormat pf, int pageIndex) {
                if (pageIndex > 0) {
                    return Printable.NO_SUCH_PAGE;
                }
                ((Graphics2D) g).translate(pf.getImageableX(),
                        pf.getImageableY());

                // Paint the canvas.
                c.paint(g);

                // Paint the image.
                if (im != null) {
                    g.drawImage(im, 32, 32, 64, 64, null);
                }

                return Printable.PAGE_EXISTS;
            }
        });
        try {
            pj.print();
        } catch (Exception z) {
            z.printStackTrace(System.err);
        }
    }

}

运行实例,输出如下错误信息:

Headless mode: true
java.awt.HeadlessException
	at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:207)
	at java.awt.Window.<init>(Window.java:536)
	at java.awt.Frame.<init>(Frame.java:420)
	at com.huangx.jdk.awt.HeadlessBasics.main(HeadlessBasics.java:38)
Frame is created: false
java.awt.HeadlessException
	at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:207)
	at java.awt.Button.<init>(Button.java:152)
	at com.huangx.jdk.awt.HeadlessBasics.main(HeadlessBasics.java:49)
Button is created: false

此时会打开打印窗口,我使用PDF进行打印。打印数据存入 tmp.pdf 文件,效果如下图:

Java 的 java.awt.headless 模式

上图得知,我们的图片被打印到了PDF文件中。当然,也可直接打到纸上面,因为它调用了打印机。

Headless mode 在 Spring Boot 中的应用

Spring Boot 在 org.springframework.boot.SpringApplication 类的 ConfigurableApplicationContext run(String... args) 方法中调用 configureHeadlessProperty(); 方法去开启 headless 模式,代码如下:

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty(); // 就是这里了
    //...
    return context;
}

configureHeadlessProperty() 方法的源码如下:

private void configureHeadlessProperty() {
   System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
         System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

其中, 常亮定义如下:

private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

参考资料:

https://www.oschina.net/translate/using-headless-mode-in-java-se 

不傲才以骄人,不以宠而作威。——诸葛亮
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号