Java Headless Mode

1. Oversigt

Nogle gange er vi nødt til det arbejde med grafikbaserede applikationer i Java uden en egentlig skærm, tastatur eller mus, lad os sige, på en server eller en container.

I denne korte vejledning lærer vi om Java's hovedløse tilstand for at løse dette scenario. Vi vil også se på, hvad vi kan gøre i hovedløs tilstand, og hvad vi ikke kan.

2. Opsætning af hovedløs tilstand

Der er mange måder, vi kan opsætte hovedløs tilstand i Java eksplicit:

  • Programmatisk indstilling af systemegenskaben java.awt. hovedløs til rigtigt
  • Brug af kommandolinjeargumentet: java -Djava.awt.headless = sandt
  • Tilføjer -Djava.awt.headless = sandt til JAVA_OPTS miljøvariabel i et serverstart script

Hvis miljøet faktisk er hovedløst, ville JVM implicit være opmærksom på det. Der vil dog være subtile forskelle i nogle scenarier. Vi ser dem snart.

3. Eksempler på UI-komponenter i hovedløs tilstand

En typisk anvendelse af UI-komponenter, der kører i et hovedløst miljø, kan være en billedkonverteringsapp. Selvom det har brug for grafikdata til billedbehandling, er en skærm ikke rigtig nødvendig. Appen kan køres på en server og konverterede filer gemmes eller sendes over netværket til en anden maskine til visning.

Lad os se dette i aktion.

Først tænder vi hovedløs tilstand programmatisk i en JUnit klasse:

@Før offentlig ugyldig setUpHeadlessMode () {System.setProperty ("java.awt.headless", "true"); } 

For at sikre, at det er konfigureret korrekt, kan vi bruge java.awt.GraphicsEnvironment#erHovedløs:

@Test offentlig ugyldig nårSetUpSuccessful_thenHeadlessIsTrue () {assertThat (GraphicsEnvironment.isHeadless ()). IsTrue (); } 

Vi skal huske på, at ovenstående test vil lykkes i et hovedløst miljø, selvom tilstanden ikke er eksplicit aktiveret.

Lad os nu se vores enkle billedkonverter:

@Test offentlig ugyldig nårHeadlessMode_thenImagesWork () {boolsk resultat = falsk; prøv (InputStream inStream = HeadlessModeUnitTest.class.getResourceAsStream (IN_FILE); FileOutputStream outStream = ny FileOutputStream (OUT_FILE)) {BufferedImage inputImage = ImageIO.read (inStream); resultat = ImageIO.write (inputImage, FORMAT, outStream); } hævder, at (resultat) .isTrue (); }

I denne næste prøve kan vi se, at oplysninger om alle skrifttyper, herunder skrifttypemetrikker, også er tilgængelige for os:

@Test offentlig ugyldig nårHeadless_thenFontsWork () {GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment (); String skrifttyper [] = ge.getAvailableFontFamilyNames (); assertThat (skrifttyper) .isNotEmpty (); Font font = ny font (skrifttyper [0], Font.BOLD, 14); FontMetrics fm = (nyt lærred ()). GetFontMetrics (font); assertThat (fm.getHeight ()). erGreaterThan (0); assertThat (fm.getAscent ()). erGreaterThan (0); assertThat (fm.getDescent ()). erGreaterThan (0); }

4. HeadlessException

Der er komponenter, der kræver perifere enheder og fungerer ikke i hovedløs tilstand. De kaster en HeadlessException når det bruges i et ikke-interaktivt miljø:

Undtagelse i tråden "main" java.awt.HeadlessException på java.awt.GraphicsEnvironment.checkHeadless (GraphicsEnvironment.java:204) ved java.awt.Window. (Window.java:536) ved java.awt.Frame. (Frame. Java: 420)

Denne test hævder, at brug af Ramme i en hovedløs tilstand vil faktisk kaste en HeadlessException:

@Test offentlig ugyldig nårHeadlessmode_thenFrameThrowsHeadlessException () {assertThatExceptionOfType (HeadlessException.class) .isThrownBy (() -> {Frame frame = new Frame (); frame.setVisible (true); frame.setSize (120, 120);}); } 

Husk som tommelfingerregel, at komponenter på øverste niveau, f.eks Ramme og Knap har altid brug for et interaktivt miljø og kaster denne undtagelse. Imidlertid, det vil blive kastet som en uoprettelig Fejl hvis hovedløs tilstand ikke er indstillet eksplicit.

5. Omgå tungvægtskomponenter i hovedløs tilstand

På dette tidspunkt stiller vi måske et spørgsmål til os selv - men hvad hvis vi har kode med GUI-komponenter til at køre på begge typer miljøer - en produktionsmaskine med hoved og en hovedløs kildekodeanalyseserver?

I ovenstående eksempler har vi set, at de tunge komponenter ikke fungerer på serveren og vil kaste en undtagelse.

Så vi kan bruge en betinget tilgang:

offentlig ugyldig FlexibleApp () {if (GraphicsEnvironment.isHeadless ()) {System.out.println ("Hello World"); } andet {JOptionPane.showMessageDialog (null, "Hello World"); }}

Ved hjælp af dette mønster kan vi oprette en fleksibel app, der justerer dens adfærd i henhold til miljøet.

6. Konklusion

Med forskellige kodeeksempler så vi hvordan og hvorfor hovedløs tilstand i java. Denne tekniske artikel giver en komplet liste over, hvad alt kan gøres, mens du kører i hovedløs tilstand.

Som normalt er kildekoden til ovenstående eksempler tilgængelig på GitHub.