Folosiți limba dinamică dinamic 1

Dezvoltatorii Java știu că Java nu este întotdeauna cea mai bună limbă pentru rezolvarea unor sarcini. Anul acesta lansările versiunilor 1.0 pentru JRuby și Groovy au sporit interesul pentru integrarea limbajelor dinamice în aplicațiile Java. Groovy, JRuby, Rhino, Jython și alte proiecte open source oferă posibilitatea de a scrie cod în așa-numitele limbi de scripting și de a le rula sub JVM. Până acum, integrarea unor astfel de limbi cu cod Java a însemnat de obicei necesitatea de a studia pentru fiecare interpret API-ul său unic și caracteristicile de implementare.







Pachet javax.script. adăugat în Java SE 6, facilitează procesul de integrare a limbilor dinamice. Acesta oferă o modalitate uniformă și ușoară de a apela mai multe limbi de scriere atunci când se utilizează un set mic de interfețe și clase reale. Dar API-ul de scripting Java este mai mult decât o ușurare în crearea fragmentelor scripturi ale aplicației; pachetul de suport pentru scripting vă permite să citiți și să invocați script-uri externe în zbor, ceea ce înseamnă că puteți modifica dinamic scripturile pentru a schimba comportamentul aplicației executabile.

Scriind împotriva dinamicii

Scripting API oferă vizibilitate bidirecțională între aplicațiile Java și scripturile externe. Codul dvs. Java nu poate să apeleze numai scripturi externe, ci poate și să ofere astfel de scripturi acces la obiecte Java selectate. Un script extern Ruby, de exemplu, poate invoca metode de obiecte Java și poate avea acces la proprietățile lor, ceea ce permite script-urilor să adauge comportament care nu a fost furnizat în momentul dezvoltării aplicației executabile.

Accesul la scripturi externe poate fi folosit pentru a extinde funcționalitatea aplicației în timpul execuției, configurației, monitorizării sau altor manipulări operaționale, cum ar fi schimbarea logicii de afaceri fără a fi nevoie să opriți aplicația. Aplicațiile posibile ale pachetului de suport pentru scripting includ:

  • Scrierea logicii de afaceri într-o limbă mai simplă decât Java, fără a recurge la medii avansate de execuție.
  • Construirea unei arhitecturi bazate pe plug-in-uri (plug-in-uri), permițând utilizatorilor să personalizeze aplicația în zbor.
  • Integrați un script existent în aplicația dvs. Java, de exemplu, un script care procesează sau convertește fișiere text.
  • Produceți o configurație operațională externă a comportamentului aplicației folosind un limbaj de programare complet în locul unui fișier de configurare.
  • Adăugați unei aplicații Java o limbă specifică domeniului subiect.
  • Utilizați limbajul de scripting în faza de prototipare a aplicației Java.
  • Scrieți în limba de scriere codul de testare pentru aplicație.

Listing 1. Principala metodă pentru HelloScriptingWorld

Sarcina principală a metodei principale () este de a obține instanța javax.script.ScriptEngine (primele două construcții din listare 1). Motorul scripting încarcă și execută scripturi pentru o anumită limbă. Aceasta este clasa cea mai frecvent utilizată și revendicată în pachetul de scripting Java. Exportați motorul script din javax.script.ScriptEngineManager (prima expresie de atribuire). O necesitate tipică este obținerea unui singur exemplu de motor în program, cu excepția cazului în care se utilizează multe limbi de scriere.

ScriptEngineManager. probabil singura clasă reală din pachetul de scripting la care veți accesa în mod regulat; majoritatea celorlalte - interfețe. Și acest lucru, probabil, este singura clasă în pachetul de scripting, copii de care se va crea în mod direct (sau indirect. - prin introducerea unui mecanism în conformitate cu (dependență injecție), așa cum se face în Cadrul de primăvară) ScriptEngineManager poate returna un motor de script într-unul din cele trei moduri :

ScriptEngineManager - găsim și creăm motoare de script în mod indirect. Ie atunci când creați copii ScriptEngine-managerii apelează la serviciul de căutare a motorului (adăugat în Java 6) pentru detectarea tuturor implementărilor înregistrate javax.script.ScriptEngineFactory în CLASSPATH Aceste clase fabrica vin în pachete cu implementări de scripting API-ul Java; cel mai probabil nu va trebui niciodată să vă ocupați direct de aceste clase.

După cum am menționat, codul dvs. utilizează o instanță a ScriptEngine pentru a executa scriptul. Motorul de scripting acționează ca un intermediar între codul dvs. de scripting și interpretul sau compilatorul limbii țintă, care execută în cele din urmă codul. Prin urmare, nu este necesar să știți ce clase sunt folosite de fiecare interpret pentru a rula codul. De exemplu, motorul de script pentru JRuby s-ar putea trece codul pentru prima dată în clasa org.jruby.Ruby exemplu, pentru a compila un script într-o formă intermediară, apoi suna din nou pentru a rula valorile script și pentru a reveni proces. Implementarea suportului de script ascunde detalii, inclusiv modul în care interpretul se potrivește cu definițiile de clasă, cu obiectele aplicației și cu fluxurile de intrare / ieșire Java.

În Fig. 1 în formă generală arată relația dintre aplicația dvs., API-ul de scripting Java, implementarea ScriptEngine și interpretul limbii de scripting. Puteți observa că aplicația dvs. se bazează numai pe API-ul scripting furnizat de clasa ScriptEngineManager și interfața ScriptEngine. Componenta de implementare a interfeței ScriptEngine servește tuturor specificelor de utilizare a unui interpret special de limbă.

Figura 1: Interrelaționările componentelor API de scriptare

Voi presupuneți că veți fi interesați de unde să obțineți fișierele JAR necesare care pun în aplicare motorul de scripting și interpretul de limbă. Cel mai bun loc pentru a găsi implementarea motorului este, în primul rând, proiectul open source Scripting, susținut de java.net (a se vedea resursele). Aici veți găsi implementări ale motoarelor script pentru mai multe limbi și legături către alte resurse pe această temă. Proiectul Scripting oferă și linkuri pentru încărcarea interpreților de limbi de scripting acceptate.







Listing 2. Metoda invokeHelloScript

Contextul execuției scriptului

Rețineți că această metodă și alte metode de clasă declară că aruncă javax.script.ScriptException. Această excepție verificată - singura specificată în pachetul de scripting - indică faptul că motorul a eșuat în parsarea sau executarea codului. Toate metodele eval () ale motorului de scripturi aruncă o ScriptException. astfel încât în ​​codul de care aveți nevoie pentru a gestiona această situație în mod corespunzător.

Listing 3. Metodele defineScriptFunction și invokeScriptFunctionFromEngine

Listing 4. Metoda invokeScriptFunctionFromJava

Avantaj script scripturi folosind proxy

Dacă funcția sau metoda de script implementează interfața Java, este disponibilă o utilizare mai avansată a aplicației Invocable. Interfața invocabilă definește metoda getInterface (). Un parametru care ia ca argument o interfață și returnează un proxy Java care implementează această interfață furnizată anterior. Odată ce ați primit obiectul proxy din motorul de script, îl puteți trata ca un obiect obișnuit Java. Metodele invocate de proxy sunt delegate unui motor scripting pentru scripting.

API-ul Java Scripting nu necesită un motor de script pentru implementarea interfeței Invocable. De fapt, codul din listare 4 ar trebui să folosească operatorul instanței înainte de a lansa tipul. Pentru a vă asigura că motorul implementează interfața invocabilă.

Exemplele din listele 3 și 4 indică modul în care codul Java poate apela funcții sau metode definite în limba scripting. Acum, probabil sunteți interesat dacă codul din limba scripting poate, la rândul său, să apeleze metodele obiectelor Java. Poate. invokeJavaFromScriptFunction () Metoda în 5 Listarea arată - modul de accesare a Java-obiecte din motorul de script și modul în care codul scriptului poate invoca metode de Java obiecte. În particular, invokeJavaFromScriptFunction (), metoda utilizează metoda prevăzută put motor () pentru a transfera o instanță a motorului clasei HelloScriptingWorld. După ce motorul are acces la obiectul Java prin numele trecut în apel pentru a pune (). Codul de script numit eval () îl folosește.

Listing 5. Metode InvokeJavaFromScriptFunction și getHelloReply

Atunci când un motor de script face ca un obiect Java să fie accesibil unui script care rulează într-un mediu de rulare, motorul trebuie să-l împacheteze într-un tip de obiect adecvat pentru limba curentă de scripting. Un astfel de pachet trebuie să efectueze conversii adecvate cu valoare obiect, de exemplu, să permită utilizarea întregului obiect Java direct în expresiile matematice ale limbajului de scripting. Aflarea modului în care obiectele Java sunt portate obiectelor de scripting este specifică fiecărui motor de scripting și depășește ceea ce este discutat în acest articol. Și totuși, trebuie să știți că o astfel de traducere se întâmplă, astfel încât să puteți testa limbajul de scripting folosit pentru a vă asigura că previziunile transformărilor sunt previzibile.

ScriptEngine.put și metoda get get () sunt principalele modalități de a distribui accesul la obiecte și date între codul Java și scripturile executabile de motor. (Pentru o discuție extinsă despre acest subiect, vedeți mai jos domeniul de aplicare al scriptului executabil.) Când apelați metoda put () de pe motor. motorul de script asociază al doilea parametru (un obiect Java arbitrar) cu cheia de șir specificată. Majoritatea motoarelor de scripting asigură disponibilitatea acestor obiecte Java în scripturi printr-un nume de variabil dat. Motoarele sunt libere să gestioneze numele pe care le transmiteți metodei put (). De exemplu, motorul de scripting JRuby face helloScriptingWorld disponibil în codul Ruby ca variabilă globală $ helloScriptingWorld. Aceasta corespunde sintaxei Ruby pentru variabilele globale.

Metoda get () a motorului extrage valorile disponibile în mediul de scripting. În general, fiecare variabilă globală și funcție din mediul înconjurător este disponibilă în codul Java prin metoda get (). Dar pentru scripturi, sunt disponibile doar acele obiecte Java care sunt declarate direct în motorul de scripturi - prin apelarea put ().

Această abilitate de a accesa și de a manipula obiecte Java într-o aplicație executabilă din scripturi externe este o tehnică puternică pentru extinderea funcționalității programelor Java. (Această tehnică este utilizată în exemplul din partea 2)

Puteți lansa aplicația HelloScriptingWorld descărcând și compilând codul sursă. Fișierul zip conține script-uri de construcție atât pentru Ant cât și pentru Maven pentru a face mai ușor compilarea și rularea aplicației probă. Efectuați următorii pași:

  1. Descărcați arhiva zip.
  2. Creați un nou director, să spuneți, script-ul java și dezarhivați arhiva de la pasul anterior.
  3. Deschideți o fereastră de comandă și navigați la acest director.
  4. Fugiți-vă și alergați-vă.

Listing 6. Ieșire dintr-un HelloScriptingWorld care rulează

API-ul Java Scripting a apărut în Java SE 6, dar îl puteți utiliza și cu Java SE 5. Trebuie doar să oferiți implementarea clasei lipsă din pachetul javax.script. Din fericire, implementarea este disponibilă din implementarea de referință Java Application Specification 223. JSR 223 definește API-ul de scripting Java.

Pentru modul în care treceți obiectele Java în script-uri executabile de script, există o implementare mai avansată decât apelurile get () și put (). Când apelați get () sau put () pe un motor, acesta extrage sau salvează cheia necesară într-o instanță special furnizată a interfeței javax.script.Bindings. (Interfața Bindings este doar o interfață Map.)

Când codul dvs. solicită metoda eval (). pe partea motorului, se folosește o cheie predefinită legată de valori. Cu toate acestea, aveți posibilitatea să furnizați propriul obiect Bindings pentru a servi apelurilor eval (). Pentru a limita vizibilitatea variabilelor și obiectelor pentru acest script. Apoi, apelul va arata ca eval (String, Bindings) sau eval (Reader, Bindings). Pentru a facilita crearea legăturilor dvs. specifice. motoarele script oferă metoda createBindings (). returnează un obiect Bindings gol. Apelul eval pe obiectul Bindings ascunde temporar obiectele Java care au fost stocate anterior utilizând predefinitul motor de legare.

Pentru acumularea istoriei, motorul scripturi are două mecanisme de legare predefinite: legăturile de domeniu ale motorului sunt utilizate pentru apelurile get () și put (). iar legarea globală a domeniului de aplicare poate fi utilizată de motor pentru a căuta obiecte în cazul în care nu pot fi detectate la nivelul de "obligație pentru motor". Formularea poate - este esențială. Mecanismele de scriptare nu sunt obligate să furnizeze disponibilitatea unei legături globale pentru scripturi. Deși multe motoare de scripting oferă astfel de acces.

Scopul constructiv „domeniu de aplicare la nivel mondial“ -svyazyvaniya - folosirea în comun de către diferite motoare de script. Fiecare motor returnat de o instanță a ScriptEngineManager. este completat cu același obiect obligatoriu global. Puteți prelua acest obiect prin apelarea getBindings (ScriptContext.GLOBAL_SCOPE) și atribuie un obiect obligatoriu la nivel mondial la motor prin setBindings (legături și ScriptContext.GLOBAL_SCOPE).

ScriptContext este o interfață care definește și gestionează contextul timpului de execuție al motorului de scripting. ScriptContext conține legături la domeniile "motor" și "global", precum și fluxurile de intrare / ieșire utilizate de motor pentru operațiile I / O standard. Puteți obține contextul motorului de script și îl puteți manipula folosind metoda getContext ().

Scripturi API concepte, cum ar fi domeniul de aplicare. legăturile obligatorii și contextul pot, la început, să fie confuze, din cauza semnificațiilor lor parțial suprapuse. Descărcarea codului sursă pentru acest articol include un fișier de test JUnit numit ScriptApiRhinoTest localizat în directorul src / test / java. Codul Java conținut acolo este destinat să vă ajute să înțelegeți aceste concepte.

Descărcări







Articole similare

Trimiteți-le prietenilor: