在Java SE平臺上使用Headless模式
這篇文章介紹怎樣在標(biāo)準(zhǔn)Java(Java SE,也稱作J2SE)平臺上用Headless模式。
Headless模式是在缺少顯示屏、鍵盤或者鼠標(biāo)時(shí)的系統(tǒng)配置。聽起來不可思議,但事實(shí)上你可以在這中模式下完成不同的操作,甚至是用圖形數(shù)據(jù)也可以。
哪里才能用到此模式呢?想想你的應(yīng)用不停的生成一張圖片,比如,當(dāng)用戶每次登陸系統(tǒng)是都要生成一張認(rèn)證圖片。當(dāng)創(chuàng)建圖片時(shí),你得應(yīng)用既不需要顯示器也不需要鍵盤。讓我們假設(shè)一下,現(xiàn)在你的應(yīng)用有個(gè)主架構(gòu)或者專有服務(wù)器,但這個(gè)服務(wù)沒有顯示器,鍵盤或者鼠標(biāo)。理想的決定是用環(huán)境的大量視覺計(jì)算能力而不是非視覺特性。在Headless模式下生成的圖片可以傳遞到Headful系統(tǒng)進(jìn)行更深層次渲染。
在java.awt.toolkit和java.awt.graphicsenvironment 類中有許多方法,除了對字體,圖像和打印的操作外還有調(diào)用顯示器,鍵盤和鼠標(biāo)的方法。但是有一些類中,比如Canvas 和 Panel,可以在headless模式下執(zhí)行。在J2SE 1.4平臺之后就提供了對Headless模式的支持。
注:這篇文章重點(diǎn)講的是Java SE6 平臺版本的文檔。任何API的增加或其他增強(qiáng)Java SE平臺的規(guī)范是由JSR270專家組(JSR 270 Expert Group.)的審查和批準(zhǔn)。
Toolkit
java.awt.Toolkit類是Abstract Window Toolkit (AWT)的 所有實(shí)現(xiàn)類的抽象父類。Toolkit的子類用于把各種AWT組件綁定到特定的本地toolkit實(shí)現(xiàn)上去。  
如果顯示設(shè)備,鍵盤或鼠標(biāo)不支持的話,很多組件都會受影響。一個(gè)合適的類構(gòu)造器應(yīng)當(dāng)拋出一個(gè)HeadlessException異常: 
- Button
 - Checkbox
 - Choice
 - Dialog
 - FileDialog
 - Frame
 - Label
 - List
 - Menu
 - MenuBar
 - MenuItem
 - PopupMenu
 - Scrollbar
 - ScrollPane
 - TextArea
 - TextField
 - Window
 
這種重量級的組件需要有一個(gè)操作系統(tǒng)級別上對等的圖形函數(shù)來支持它,在headless的機(jī)器上它們將不能正常工作。  
與Canvas、Panel和Image組件相關(guān)的組件不需要拋出HeadlessException異常,因?yàn)檫@些組件在操作系統(tǒng)級別上的對等圖形函數(shù)可以使用空函數(shù),然后作為輕量級組件來處理。
一個(gè)Headless的toolkit也會把Java組件綁定到本地資源上去,但是它只有在資源中不包含顯示設(shè)備或輸入設(shè)備時(shí)才會這樣做。
Graphics Environment
java.awt.GraphicsEnvironment類是一個(gè)抽象類,它描述了在給定平臺中,可以在Java技術(shù)中使用的由 GraphicsDevice對象和Font對象組成的集合。該GraphicsEnvironment中的資源可以是本地的也可以是遠(yuǎn)程設(shè)備。 GraphicsDevice對象可以是顯示器,打印機(jī)或者圖形緩存等,并且它們是Graphics2D 繪制函數(shù)的目標(biāo)。每一個(gè)GraphicsDevice都有許多與之關(guān)聯(lián)的GraphicsConfiguration對象。這些對象指定了不同的配置環(huán)境,在這些配置環(huán)境中可以使用GraphicsDevice。
Table 1 顯示GraphicsEnvironment 方法,檢查Headless模式支持
Table 1. Headless 模式方法
| 方法 | 描述 | 
|---|---|
| 
             public static boolean   | 
            
             測試環(huán)境是否為headless, 對于是否不支持display device,keyboard,mouse。如果這個(gè)方法returns true,theToolkitandGraphicsEnvironmentclasses 拋出(thrown)依賴于display device, keyboard, mouse的aHeadlessExceptionis異常.  | 
        
| 
             public boolean   | 
            
             Returns thisGraphicsEnvironmentcan 是否支持dieplay device,keyboard,mouse. 如果這個(gè)方法 returns true, theGraphicsEnvironmentthat 拋出(throw)一個(gè)依賴于 display device, keyboard, mouse的aHeadlessExceptionis 異常.  | 
        
注意:isHeadless()方法檢查特定的系統(tǒng)屬性,java.awt.headless而不是系統(tǒng)的硬件配置.
HeadlessException 拋出的代碼,這取決于display device、keyboard、mouse在一個(gè)環(huán)境稱為不支持任何這些.唯一的例外是來自一個(gè) UnsupportedOperationException,本身就是來源于一個(gè)RuntimeException.
設(shè)置Headless模式
使用Headless模式操作,您必須首先了解如何檢查和設(shè)置系統(tǒng)屬性與此相關(guān)的模式。此外,你必須了解如何創(chuàng)建一個(gè)默認(rèn)的工具包使用工具箱的無頭實(shí)現(xiàn)類.
系統(tǒng)屬性配置
為了啟用headless模式,需要使用setProperty()方法去設(shè)置相應(yīng)的系統(tǒng)屬性。本方法可以讓你用期望的值來設(shè)置系統(tǒng)屬性。
- System.setProperty("java.awt.headless", "true");
 
上面的代碼中,java.awt.headless是一個(gè)系統(tǒng)屬性,true是我們設(shè)定的值。
如果你想在一個(gè)相同的程序中使用headless和傳統(tǒng)環(huán)境,你可以使用下面的命令行來完成:
- java -Djava.awt.headless=true
 
創(chuàng)建默認(rèn)Toolkit
如果名字為java.awt.headless的系統(tǒng)屬性被設(shè)置為true,那么headless工具包就會被使用。接下來使用getDefaultToolkit()方法來創(chuàng)建一個(gè)headless toolkit的實(shí)例:
- Toolkit tk = Toolkit.getDefaultToolkit();
 
Headless模式檢查 
要檢查Headless模式的可用性,使用GraphicsEnvironment類的isHeadless()方法:
- GraphicsEnvironment ge =
 - GraphicsEnvironment.getLocalGraphicsEnvironment();
 - boolean headless_check = ge.isHeadless();
 
該方法檢查java.awt.headless系統(tǒng)屬性。如果這個(gè)屬性有一個(gè)為true的值,那么就會從工具包和依賴于一個(gè)顯示器,鍵盤,鼠標(biāo)的GraphicsEnvironment類的區(qū)域中拋出一個(gè)HeadlessException。 
在Headless模式中操作 
設(shè)置好headless模式并創(chuàng)建一個(gè)headless工具包的實(shí)例后,您的應(yīng)用程序可以執(zhí)行以下操作: 
- 創(chuàng)建輕量級組件,如Canvas,Panel,和Swing組件,除了top級別.
 - 收集關(guān)于可用的字體、字體指標(biāo)和字體設(shè)置的信息
 - 設(shè)置顏色來渲染文本和圖形
 - 創(chuàng)造和獲取圖像,為渲染準(zhǔn)備圖片
 - 使用java.awt.PrintJob, java.awt.print.*, 和 javax.print.* 類進(jìn)行打印。
 - 發(fā)出"嗶嗶"音頻。
 
Canvas(畫布)
下面的代碼會在屏幕上繪制出一個(gè)空白的矩形區(qū)域,你可以在上面繪制線條。可以使用Canvas類創(chuàng)建一個(gè)新的Canvas組件。
- final Canvas c = new Canvas()
 - {
 - public void paint(Graphics g)
 - {
 - Rectangle r = getBounds();
 - g.drawLine(0, 0, r.width - 1, r.height - 1);
 - g.drawLine(0, r.height - 1, r.width - 1, 0);
 - }
 - };
 
Fonts(字體)
這段代碼顯示了怎么使用Font類畫一個(gè)文本字符串并設(shè)置文字的字體。Graphics對象是用來繪制這個(gè)字符串的。
- public void paint(Graphics g)
 - {
 - g.setFont(new Font("Arial", Font.ITALIC, 12));
 - g.drawString("Test", 32, 8);
 - }
 
Colors
這段代碼顯示了如何使用指定的紅,綠,藍(lán)的值來設(shè)置一條線的顏色。Graphics對象是用來繪制這條線的。
- public void paint(Graphics g)
 - {
 - g.setColor(new Color(255, 127, 0));
 - g.drawLine(0, r.height - 1, r.width - 1, 0);
 - }
 
Images
在下面的代碼中,javax.imageio.ImageIO類的使用read()方法對圖1所示的grapefruit.jpg文件進(jìn)行解碼,并返回一個(gè)緩存圖片。
- Image i = null;
 - try
 - {
 - File f = new File("grapefruit.jpg");
 - i = ImageIO.read(f);
 - }
 - catch (Exception z)
 - {
 - z.printStackTrace(System.err);
 - }
 
圖1。grapefruit.jpg圖像文件
這段代碼演示了如何打印已經(jīng)準(zhǔn)備好的畫布,你可以使用paint方法自定義打印機(jī)的的默認(rèn)畫面。
- 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 canvas.
 - c.paint(g);
 - return Printable.PAGE_EXISTS;
 - }
 - });
 
Beep
下面的這段代碼展示了如果使用 Toolkit類的beep方法發(fā)出嘟嘟聲。
- Toolkit tk = Toolkit.getDefaultToolkit();
 - tk.beep();
 
#p#
使用Headless模式簡單例子
以下的HeadlessBasics例子運(yùn)用了文章中描述的所有功能。
要運(yùn)行這個(gè)的例子,需要用javac對下面的代碼進(jìn)行編譯。復(fù)制grapefruit.jpg圖片文件到HeadlessBasics類所在的目錄下面。
- import java.awt.*;
 - import java.io.*;
 - import java.awt.print.*;
 - import javax.imageio.*;
 - 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");
 - // 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.
 - g.setColor(new Color(255, 127, 0));
 - g.drawLine(0, r.height - 1, r.width - 1, 0);
 - // And fonts
 - 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.
 - Image i = null;
 - try
 - {
 - File f = new File("grapefruit.jpg");
 - i = ImageIO.read(f);
 - }
 - catch (Exception z)
 - {
 - z.printStackTrace(System.err);
 - }
 - final Image im = i;
 - // Print system is available.
 - 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);
 - }
 - }
 - }
 
圖2顯示了這個(gè)例子中的打印輸出結(jié)果。
圖2。HeadlessBasics的打印輸出。
此外,你可以看到以下的信息:
- Headless mode: true
 - java.awt.HeadlessException
 - at java.awt.GraphicsEnvironment.checkHeadless(Unknown Source)
 - at java.awt.Window.<init>(Unknown Source)
 - at java.awt.Frame.<init>(Unknown Source)
 - at HeadlessBasics.main(HeadlessBasics.java:24)
 - Frame is created: false
 - java.awt.HeadlessException
 - at java.awt.GraphicsEnvironment.checkHeadless(Unknown Source)
 - at java.awt.Button.<init>(Unknown Source)
 - at HeadlessBasics.main(HeadlessBasics.java:39)
 - Button is created: false
 
注:出于演示的目的,最初的代碼會導(dǎo)致此應(yīng)用程序拋出2個(gè)java.awt.HeadlessExceptions異常。
作為上一種方式的替代,你可以把標(biāo)準(zhǔn)輸出信息放到一個(gè)文件中,然后把文件打印出來。在這種情況下,使用下面的命令行來運(yùn)行這個(gè)例子:
java HeadlessBasics 2> standard_output.txt
把現(xiàn)有的應(yīng)用程序轉(zhuǎn)換為Headless模式。
你怎么把現(xiàn)有的應(yīng)用程序轉(zhuǎn)換為可執(zhí)行的headless模式?要執(zhí)行此轉(zhuǎn)換的最有效的方法是分析你的源代碼以確定任何的功能都是依賴于Headless模式的。換句話說,要實(shí)現(xiàn)相同的功能,你必須找到那些會拋出HeadlessException異常的類和方法,然后使用獨(dú)立的headless模式替換這些類和方法。
你可以使用Java SE 6 API說明來判斷一個(gè)特定的類或方法是否支持headless模式。如果一個(gè)特定的組件不支持headless模式,你的程序需要捕獲的唯一的異常是 HeadlessException。它會在其它可能的異常之前被拋出。這也是為什么在本節(jié)的代碼示例"舉例: 使用Headless模式"中,沒有什么特殊的必要性來捕獲其它異常。
你肯定會發(fā)現(xiàn)其它有用的方法來使用headless模式帶來的好處。我們希望本文能幫你完成此項(xiàng)任務(wù),在Java SE平臺中玩出一片新天地。
獲取更多信息
AWT Enhancements in J2SE 1.4: Headless Support
J2SE 1.4 platform documentation: HeadlessException
The New Modality API in Java SE 6
The java.awt.Toolkit Class
The java.awt.GraphicsEnvironment Class
關(guān)于作者
Artem Ananiev 是位于 Saint Petersburg的Sun Microsystems公司的一名軟件工程師,俄羅斯人。之前他曾經(jīng)在Abstract Window Toolkit (AWT) 項(xiàng)目中工作過幾年,他主要的技能領(lǐng)域是模態(tài),機(jī)器人和多屏系統(tǒng)。
Alla Redko 是位于 Saint Petersburg的 Sun Microsystems公司的技術(shù)作者,俄羅斯人。她為AWT項(xiàng)目編寫技術(shù)文檔,并且負(fù)責(zé)更新Java用戶手冊。在到Sun任職之前,她已經(jīng)作為技術(shù)作者工作了八年。
英文原文:Using Headless Mode in the Java SE Platform
譯文鏈接:http://www.oschina.net/translate/using-headless-mode-in-java-se















 
 
 





 
 
 
 