JDK 1.8 nashorn engine use

I have sorted out some recent technical research on the project and hope to discuss and exchange with you.

In the calculation module of liquidation project, nashorn, the js engine of jdk 1.8, is used for calculation Some simple tests have been done to nashorn in the process of using.

Using nashorn to compile js and perform invokeFunction calculation, a simple logic judgment plus a simple multiplication operation cycle can take about 600~700ms to execute 100w times

Using mozilla's rhino js engine, we compile js and perform func.call calculation. The total time is about 1400ms.

It takes a lot of time to compile js with eval method in nashorn, so it needs to be cached in practice.

In addition, using the nashorn procedure does not always call the internal js method.

Here's how it's used

public class LiquidationUtil {
    private static Logger logger = LoggerFactory.getLogger(LiquidationUtil.class);
     
    public static final String _expression = "_expression";
    public static final String _conditions = "_conditions";
    // Generate calculation object of liquidation rule
    public static Invocable  generateLiquidationFuction(String conditions,String expressionMark,String expressionParam) throws ScriptException, NoSuchMethodException {//Liquidation
        StringBuffer sb = new StringBuffer(128);
        if(StringUtils.isEmpty(conditions))
            conditions = "true";
         
        sb.append("var ").append(_conditions).append(" = function (m,o) {")
            .append("\nreturn ").append(_conditions).append("(m,o,null);\n")
        .append("};\n");
        sb.append("var ").append(_expression).append(" = function (m,o) {")
            .append("\nreturn ").append(_expression).append("(m,o,null);\n")
        .append("};\n");
         
        // condition
        sb.append("var ").append(_conditions).append(" = function (m,o,jh) {")
            .append("\nreturn ").append(conditions).append(";\n")
        .append("};\n");
         
         
        String expressionJs = expressionMap.get(expressionMark);
        // Calculation
        sb.append("var ").append(_expression).append(" = function (m,o,jh) {")
            .append("\nvar result=null;\n")
            .append("\n var ").append(expressionParam).append(";\n")
            .append("\n").append(expressionJs).append(";\n")
            .append("\nreturn result;\n")
        .append("};");
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");//nashorn javascript
        engine.eval(sb.toString());
        return (Invocable) engine;
    }
     
     
     
     
    private static final Map<String, String> expressionMap = new HashMap<String, String>();
    static {
        try {
            String path = Thread.currentThread().getContextClassLoader().getResource("liquidation_script").getFile();
            logger.info("Load clearing rules js Script path: {}", path);
            File dir = new File(path);
            for(File script : dir.listFiles()) {
                String fileName = script.getName();
                String filePath = script.getAbsolutePath();
                logger.info("Load clearing rule script mark:{}\tfilePath:{}",fileName, filePath);
                expressionMap.put(fileName.substring(0, fileName.length()-3), readFileContent(filePath));
            }
        } catch (IOException e) {
            logger.error("Error initializing fee rule script", e);
        }
    }
    public static String readFileContent(String uri) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(uri));
        String line = "";
        StringBuffer buffer = new StringBuffer();
        while ((line = br.readLine()) != null) {
            buffer.append(line).append("\n");
        }
        String fileContent = buffer.toString();
        return fileContent;
    }
}
//Call:
            jsInvocable = (Invocable)LiquidationUtil.generateLiquidationFuction(conditionsJs, expressionMark, expressionParam);// Caching for invocable
            result = jsInvocable.invokeFunction(_conditions, mapping, orderInfo);

The format of js code is

var func1 = function(param1, param2){

...

}

var func2 = function(param1, param2){

...

}

Perform eval on this string to get Invocable,

You can then invoke the js method by executing Invocable.invokeFunction("func1", param1, param2).

Tags: Java JDK Javascript

Posted on Mon, 04 Nov 2019 12:11:21 -0800 by arion279