0

Nashorn trong Java8. a new Scripting Engine

Giới thiệu

Sự ra đời của java8 trong năm 2014 này có rất nhiều thay đổi mới trong đó chúng ta phải kể đến việc phát triển Nashorn Engine nhằm thay thế cho Rhino Engine cũ và tích hợp chúng vào trong JVM để làm cho lập trình java và javascript trở nên dễ dàng hơn và có hiệu năng cao hơn. trong bài này tôi giới thiệu với các bạn về Nashorn và cách sử dụng chúng trong java8.

Nashorn là gì?

Nashorn là một "JavaScript engine" được phát triển trong ngôn ngữ java bởi oracle. nó được phát triển dựa vào " Da Vinci Machine (JSR 292) " và được released cùng với java8. trong năm 2014.

Việc thực thi javascript trên jvm chủ yếu dựa vào việc thực thi "invokeDynamic" đã được giới thiệu trong java 7.

Tại sao Nashorn lại được phát triển?

Nó được phát triển để thay thế cho javascript engine đã quá cũ trong jvm từ năm 1997 Tạo ra cầu nối giữa java và javascript. ( cây cầu này được tạo ra trong môi trường JVM) Giải quyết vấn đề không tương thích giữa java và javascript.

Nâng cao performance của việc thực thi javascript trong java. thay thế cho Rhino engine đã quá lỗi thời.

Bằng việc tích hợp javascript trong java code. bạn có thể chỉnh sửa, mở rộng, sử dụng các ưu điểm của các api có sẵn trong java. (nghĩa là bạn có thể truy cập và sử dụng các thư viện có sẵn trong java để thực thi từ javascript)

Script engine & script language là gì?

Scripting engine: là một trình thông dịch của các ngôn ngữ scripting. được viết sẵn trong java JDK nằm trong javax.script package.

Script language: là ngôn ngữ lập trình có hỗ trợ có khả năng viết các script (php,ruby, python , javascript..). đối với các ngôn ngữ cần biên dịch như java, .net thì cần phải có trình biên dịch dịch ra mã bytecodes trước khi chúng được chạy. còn đối với script language thì chúng chỉ được dịch tại thời điểm chạy. bởi một script engine.

Hầu hết các script language đều là có khai báo các kiểu dữ liệu động. (nghĩa là có thể khai báo các kiểu dữ liệu khác nhau cho cùng một biến., và khi bạn tạo một biến cũng không cần phải khai báo kiểu dữ liệu. chỉ khi nào bạn chạy nó thì mới cần khai báo.).

Tài liệu "Java Specification Request (JSR) 223" có mô tả rõ những vấn đề gặp phải khi tích hợp java và javascript trong java.http://jcp.org/en/jsr/detail?id=223

Javascripting API:?

Nó là sự cài đặt JSR 223 trong ứng dụng java. nhằm để nhúng javascript vào trong java.

Nashorn engine

Là một javascript engine viết dựa trên tài liệu mô tả của ECMAScript (javascript) engine được tích hợp trong JDK. nó đã được phát triển đầy đủ bởi oracle và được tích hợp trong jdk8. tương thích hoàn toàn với javascript.

Làm thế nào để sử dụng Nashorn?

Cần import thư viện javax.script.*; để sử dụng script engine trong java. khởi tạo một đối tượng Nashorn Script Engine sử dụng ScriptEngineManager của java. sử dụng script engine vừa tạo để thực hiện một đoạn mã javascript. VD :

 import javax.script.*;
 public class EvalScript {
 public static void main(String[] args) throws Exception {
 ScriptEngineManager manager = new ScriptEngineManager();
 ScriptEngine engine = manager.getEngineByName("nashorn");
    // evaluate JavaScript code
   engine.eval("print('Hello, World')");
 }}

Các cách sử dụng các thư viện có sẵn của java bằng script engine

sử dụng các class của java.

import javax.script.*;
public class EvalFile {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code
    engine.eval(new java.io.FileReader("script.js"));
}}

Đưa một object của java thành một biến global của script engine:

import javax.script.*;
import java.io.*;
public class ScriptVars { public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine =  manager.getEngineByName("nashorn");

    // create File object
    File f = new File("test.txt");
    // expose File object as a global variable to the engine
    engine.put("file", f);
    // evaluate JavaScript code and access the variable
    engine.eval("print(file.getAbsolutePath())");
}}

Thực thi một Script function từ script engine.

  import javax.script.*;
  public class InvokeScriptFunction {
  public static void main(String[] args) throws Exception {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines a function with one parameter
    engine.eval("function hello(name) { print('Hello, ' + name) }");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // invoke the function named "hello" with "Scripting!" as the argument
    inv.invokeFunction("hello", "Scripting!");
}
}

Thực thi một script method của object

 import javax.script.*;
 public class InvokeScriptMethod {
 public static void main(String[] args) throws Exception {
 ScriptEngineManager manager = new ScriptEngineManager();
 ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines an object with one method
    engine.eval("var obj = new Object()");
    engine.eval("obj.hello = function(name) { print('Hello, ' + name) }");

    // expose object defined in the script to the Java application
    Object obj = engine.get("obj");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // invoke the method named "hello" on the object defined in the script
    // with "Script Method!" as the argument
    inv.invokeMethod(obj, "hello", "Script Method!");
   }}

chú ý: không phải tất các các script engine đều được cài đặt Invocable interface. trong ví dụ trên thì chúng ta sử dụng nashorn engine đã được cài đặt invocabkle interface.

Cài đặt một java interface bằng script functions:

   public class ImplementRunnable {
   public static void main(String[] args) throws Exception {
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines a function with one parameter
    engine.eval("function run() { print('run() function called') }");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // get Runnable interface object
    Runnable r = inv.getInterface(Runnable.class);

    // start a new thread that runs the script
    Thread th = new Thread(r);
    th.start();
    th.join();
} }

Cài đặt một java interface bằng script object methods.

  import javax.script.*;
  public class ImplementRunnableObject {
  public static void main(String[] args) throws Exception {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines a function with one parameter
    engine.eval("var obj = new Object()")
    engine.eval("obj.run = function() { print('obj.run() method called') }");

    // expose object defined in the script to the Java application
    Object obj = engine.get("obj");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // get Runnable interface object
    Runnable r = inv.getInterface(obj, Runnable.class);

    // start a new thread that runs the script
    Thread th = new Thread(r);
    th.start();
    th.join();
 } }
Sử dụng biến trong các phạm vi khác nhau.

  public class MultipleScopes {
  public static void main(String[] args) throws Exception {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("nashorn");

    // set global variable
    engine.put("x","hello");

    // evaluate JavaScript code that prints the variable (x = "hello")
    engine.eval("print(x)");

    // define a different script context
    ScriptContext newContext = new SimpleScriptContext();
    newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
    Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);

    // set the variable to a different value in another scope

    engineScope.put("x", "world");

    // evaluate the same code but in a different script context (x = "world")
    engine.eval("print(x)", newContext);
} }

sử dụng truy cập đến các thư viện có sẵn của java trong script engine

  • primitive data type:
   var ArrayList = Java.type("java.util.ArrayList");
   var intType = Java.type("int");
   var StringArrayType = Java.type("java.lang.String[]");
   var int2DArrayType = Java.type("int[][]");
  • Object data type:
      var ArrayList = Java.type("java.util.ArrayList");
      var defaultSizeArrayList = new ArrayList;
      var customSizeArrayList = new ArrayList(16);

Truy cập inner class bằng $ sign:

var Float = Java.type("java.awt.geom.Arc2D$Float");

sử dụng import class or package:

   // Load compatibility script
   load("nashorn:mozilla_compat.js");
   // Import the java.awt package
   importPackage(java.awt);
 // Import the java.awt.Frame class
  importClass(java.awt.Frame);
  // Create a new Frame object
  var frame = new java.awt.Frame("hello");
  // Call the setVisible() method
  frame.setVisible(true);
  // Access a JavaBean property
  print(frame.title);

Nashorn thực sự là một cầu nối giữa java và javascript. nó thực sự đã làm cho việc thực thi nhiều ngôn ngữ trong java trở nên dễ dàng hơn, nâng cao hiệu năng xử lý javascript trong java


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.