Sprievodca rozhraním java.lang.ProcessBuilder API

1. Prehľad

Procesové rozhranie API poskytuje výkonný spôsob vykonávania príkazov operačného systému v prostredí Java. Má však niekoľko možností, vďaka ktorým môže byť ťažkopádne pracovať.

V tomto návode sa pozrieme na to, ako to Java zmierňuje pomocou ProcessBuilder API.

2. ProcessBuilder API

The ProcessBuilder trieda poskytuje metódy na vytváranie a konfiguráciu procesov operačného systému. Každý ProcessBuilder inštancia nám umožňuje spravovať kolekciu atribútov procesu. Potom môžeme začať nový Proces s týmito danými atribútmi.

Tu uvádzame niekoľko bežných scenárov, kde by sme mohli použiť toto API:

  • Nájdite aktuálnu verziu Java
  • Pripravte si vlastnú mapu kľúč - hodnota pre naše prostredie
  • Zmeňte pracovný adresár, kde je spustený náš príkaz shellu
  • Presmerujte vstupné a výstupné toky na vlastné náhrady
  • Zdediť oba prúdy aktuálneho procesu JVM
  • Vykonajte príkaz shellu z kódu Java

V nasledujúcich častiach sa pozrieme na praktické príklady každého z nich.

Ale predtým, ako sa ponoríme do pracovného kódu, poďme sa pozrieť na to, akú funkcionalitu toto API poskytuje.

2.1. Zhrnutie metódy

V tejto časti, urobíme krok späť a v krátkosti sa pozrieme na najdôležitejšie metódy v ProcessBuilder trieda. To nám pomôže, keď sa neskôr ponoríme do niekoľkých skutočných príkladov:

  • ProcessBuilder (príkaz String ...)

    Na vytvorenie nového nástroja na tvorbu procesov so zadaným programom a argumentmi operačného systému môžeme použiť tento pohodlný konštruktor.

  • adresár (adresár súborov)

    Môžeme prepísať predvolený pracovný adresár aktuálneho procesu volaním adresár metóda a absolvovanie a Súbor objekt. Predvolene je aktuálny pracovný adresár nastavený na hodnotu vrátenú parametrom pouzivatel.dir systémový majetok.

  • prostredie ()

    Ak chceme získať súčasné premenné prostredia, môžeme jednoducho zavolať prostredie metóda. Vráti nám kópiu súčasného procesného prostredia, ktoré používa System.getenv () ale ako Mapa .

  • inheritIO ()

    Ak chceme určiť, že zdroj a cieľ nášho štandardného I / O štandardu podprocesu by mali byť rovnaké ako v prípade súčasného procesu Java, môžeme použiť dedičstvo metóda.

  • redirectInput (súbor súboru), redirectOutput (súbor súborov), redirectError (súbor súborov)

    Ak chceme presmerovať štandardný vstup, výstup a cieľ chyby nástroja na tvorbu procesu na súbor, máme k dispozícii tieto tri podobné metódy presmerovania.

  • štart ()

    V neposlednom rade na spustenie nového procesu s tým, čo sme nakonfigurovali, jednoducho zavoláme štart ().

Mali by sme poznamenať, že táto trieda NIE JE synchronizovaná. Napríklad, ak máme viac vlákien prístupových k a ProcessBuilder inštancia súčasne, potom musí byť synchronizácia riadená externe.

3. Príklady

Teraz, keď máme základné znalosti o ProcessBuilder API, prejdime si niekoľko príkladov.

3.1. Použitím ProcessBuilder na vytlačenie verzie Java

V tomto prvom príklade spustíme program java príkaz s jedným argumentom za účelom získania verzie.

Proces process = new ProcessBuilder ("java", "-version"). Start ();

Najskôr vytvoríme náš ProcessBuilder objekt odovzdávajúci hodnoty príkazu a argumentu konštruktoru. Ďalej začneme proces pomocou štart () metóda na získanie a Proces objekt.

Teraz sa pozrime, ako zvládnuť výstup:

Zoznam výsledkov = readOutput (process.getInputStream ()); assertThat ("Výsledky by nemali byť prázdne", výsledky, sú (nie (prázdne ()))); assertThat ("Výsledky by mali obsahovať java verziu:", results, hasItem (containsString ("java verzia"))); int exitCode = process.waitFor (); assertEquals ("Nemali by sa zistiť žiadne chyby", 0, exitCode);

Tu čítame výstup procesu a overujeme, či je obsah taký, aký očakávame. V poslednom kroku čakáme na dokončenie procesu process.waitFor ().

Po dokončení procesu nám návratová hodnota hovorí, či bol proces úspešný alebo nie.

Je potrebné pamätať na niekoľko dôležitých bodov:

  • Argumenty musia byť v správnom poradí
  • V tomto príklade sa navyše použije predvolený pracovný adresár a prostredie
  • Schválne sa neozývame process.waitFor () až po prečítaní výstupu, pretože výstupná vyrovnávacia pamäť môže zastaviť proces
  • Urobili sme predpoklad, že java príkaz je k dispozícii prostredníctvom CESTA premenná

3.2. Spustenie procesu s upraveným prostredím

V tomto ďalšom príklade sa pozrieme na to, ako upraviť pracovné prostredie.

Ale predtým, ako to urobíme, začnime pohľadom na druh informácií, ktoré môžeme nájsť v predvolenom prostredí:

ProcessBuilder processBuilder = nový ProcessBuilder (); Mapové prostredie = processBuilder.environment (); environment.forEach ((kľúč, hodnota) -> System.out.println (kľúč + hodnota));

Toto jednoducho vytlačí každú z premenných položiek, ktoré sú poskytované v predvolenom nastavení:

PATH / usr / bin: / bin: / usr / sbin: / sbin SHELL / bin / bash ...

Teraz do našej pridáme novú premennú prostredia ProcessBuilder objekt a spustením príkazu na výstup jeho hodnoty:

environment.put ("GREETING", "Hola Mundo"); processBuilder.command ("/ bin / bash", "-c", "echo $ GREETING"); Proces proces = processBuilder.start ();

Poďme si rozložiť kroky, aby sme pochopili, čo sme urobili:

  • Pridajte do nášho prostredia premennú nazvanú „GREETING“ s hodnotou „Hola Mundo“, ktorá je štandardom Mapa
  • Tentokrát namiesto použitia konštruktora sme nastavili príkaz a argumenty pomocou príkaz (reťazec ... príkaz) metóda priamo.
  • Potom začneme náš proces podľa predchádzajúceho príkladu.

Na dokončenie príkladu overíme, že výstup obsahuje náš pozdrav:

Zoznam výsledkov = readOutput (process.getInputStream ()); assertThat ("Výsledky by nemali byť prázdne", výsledky, sú (nie (prázdne ()))); assertThat ("Výsledky by mali obsahovať java verziu:", results, hasItem (containsString ("Hola Mundo")));

3.3. Spustenie procesu so zmeneným pracovným adresárom

Niekedy môže byť užitočné zmeniť pracovný adresár. V našom ďalšom príklade uvidíme, ako to urobiť:

@ Test public void givenProcessBuilder_whenModifyWorkingDir_thenSuccess () vyvolá IOException, InterruptedException {ProcessBuilder processBuilder = nový ProcessBuilder ("/ bin / sh", "-c", "ls"); processBuilder.directory (nový súbor ("src")); Proces proces = processBuilder.start (); Zoznam výsledkov = readOutput (process.getInputStream ()); assertThat ("Výsledky by nemali byť prázdne", výsledky, sú (nie (prázdne ()))); assertThat ("Výsledky by mali obsahovať zoznam adresárov:", results, contains ("main", "test")); int exitCode = process.waitFor (); assertEquals ("Nemali by sa zistiť žiadne chyby", 0, exitCode); }

Vo vyššie uvedenom príklade sme nastavili pracovný adresár na projekt src d pomocou pohodlnej metódy adresár (adresár súborov). Potom spustíme jednoduchý príkaz na výpis adresárov a skontrolujeme, či výstup obsahuje podadresáre hlavný a test.

3.4. Presmerovanie štandardného vstupu a výstupu

V reálnom svete pravdepodobne budeme chcieť zachytiť výsledky našich bežiacich procesov v protokolovom súbore na ďalšiu analýzu. Našťastie ProcessBuilder API má zabudovanú podporu presne pre toto, ako uvidíme v tomto príklade.

V predvolenom nastavení náš proces číta vstup z potrubia. K tomuto kanálu môžeme pristupovať cez výstupný prúd vrátený serverom Process.getOutputStream ().

Ako však čoskoro uvidíme, štandardný výstup môže byť pomocou metódy presmerovaný na iný zdroj, napríklad do súboru redirectOutput. V tomto prípade, getOutputStream () vráti a ProcessBuilder.NullOutputStream.

Vráťme sa k nášmu pôvodnému príkladu a vytlačme si verziu Java. Teraz však presmerujeme výstup na súbor protokolu namiesto štandardného výstupného potrubia:

ProcessBuilder processBuilder = nový ProcessBuilder ("java", "-version"); processBuilder.redirectErrorStream (true); Protokol súboru = folder.newFile ("java-version.log"); processBuilder.redirectOutput (log); Proces proces = processBuilder.start ();

Vo vyššie uvedenom príklade vytvoríme nový dočasný súbor s názvom log a povieme náš ProcessBuilder presmerovať výstup na tento cieľ súboru.

V tomto poslednom úryvku to jednoducho skontrolujeme getInputStream () je skutočne nulový a že obsah nášho súboru je podľa očakávania:

assertEquals ("Ak je presmerovaný, mal by byť -1", -1, process.getInputStream (). read ()); Zoznam riadkov = Files.lines (log.toPath ()). Collect (Collectors.toList ()); assertThat ("Výsledky by mali obsahovať java verziu:", lines, hasItem (containsString ("java verzia")));

Teraz sa pozrime na miernu variáciu na tomto príklade. Napríklad keď chceme namiesto súboru zakaždým pridať nový k súboru protokolu:

Protokol súboru = tempFolder.newFile ("java-version-append.log"); processBuilder.redirectErrorStream (true); processBuilder.redirectOutput (Redirect.appendTo (log));

Je tiež dôležité spomenúť výzvu na číslo redirectErrorStream (true). V prípade akýchkoľvek chýb bude chybový výstup zlúčený do normálneho výstupného súboru procesu.

Môžeme samozrejme určiť jednotlivé súbory pre štandardný výstup a štandardný chybový výstup:

Súbor outputLog = tempFolder.newFile ("standard-output.log"); Súbor errorLog = tempFolder.newFile ("error.log"); processBuilder.redirectOutput (Redirect.appendTo (outputLog)); processBuilder.redirectError (Redirect.appendTo (errorLog));

3.5. Dedenie I / O súčasného procesu

V tomto predposlednom príklade uvidíme inheritIO () metóda v akcii. Túto metódu môžeme použiť, keď chceme presmerovať I / O podprocesov na štandardné I / O aktuálneho procesu:

@Test public void givenProcessBuilder_whenInheritIO_thenSuccess () vyvolá IOException, InterruptedException {ProcessBuilder processBuilder = nový ProcessBuilder ("/ bin / sh", "-c", "echo ahoj"); processBuilder.inheritIO (); Proces proces = processBuilder.start (); int exitCode = process.waitFor (); assertEquals ("Nemali by sa zistiť žiadne chyby", 0, exitCode); }

Vo vyššie uvedenom príklade pomocou inheritIO () metóda vidíme výstup jednoduchého príkazu v konzole v našom IDE.

V nasledujúcej časti sa pozrieme na to, aké doplnky boli urobené ProcessBuilder API v Jave 9.

4. Doplnky Java 9

Java 9 predstavila koncept potrubí do ProcessBuilder API:

verejný statický zoznam startPipeline (tvorcovia zoznamov) 

Pomocou startPipeline metódou môžeme odovzdať zoznam ProcessBuilder predmety. Táto statická metóda potom spustí a Proces pre každý ProcessBuilder. Teda vytvorenie reťazca procesov, ktoré sú prepojené ich štandardným výstupom a štandardnými vstupnými tokmi.

Napríklad, ak chceme spustiť niečo také:

Nájsť . -name * .java -typ f | wc -l

To, čo by sme urobili, je vytvoriť nástroj na tvorbu procesov pre každý izolovaný príkaz a zostaviť ich do potrubia:

@Test public void givenProcessBuilder_whenStartingPipeline_thenSuccess () vyvolá IOException, InterruptedException {List builders = Arrays.asList (new ProcessBuilder ("find", "src", "-name", "* .java", "-type", "f") , nový ProcessBuilder ("wc", "-l")); Zoznam procesov = ProcessBuilder.startPipeline (stavitelia); Posledný proces = procesy.get (procesy.size () - 1); Zoznamový výstup = readOutput (last.getInputStream ()); assertThat ("Výsledky by nemali byť prázdne", výstup, je (nie (prázdny ()))); }

V tomto príklade hľadáme všetky súbory Java vo vnútri súboru src adresár a výsledky vložením do iného procesu spočítať.

Ak sa chcete dozvedieť viac o ďalších vylepšeniach vykonaných v rozhraní Process API v prostredí Java 9, prečítajte si náš skvelý článok o vylepšeniach rozhrania Java 9 Process API.

5. Záver

Aby sme to zhrnuli, v tomto tutoriáli sme preskúmali java.lang.ProcessBuilder API podrobne.

Najprv sme začali vysvetlením, čo sa dá s API urobiť, a zhrnuli sme najdôležitejšie metódy.

Ďalej sme sa pozreli na niekoľko praktických príkladov. Nakoniec sme sa pozreli na to, aké nové prírastky boli do API v Jave 9 zavedené.

Celý zdrojový kód článku je ako vždy k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found