在Servlet中重用Nashorn ScriptEngine [英] Reuse Nashorn ScriptEngine in Servlet

查看:412
本文介绍了在Servlet中重用Nashorn ScriptEngine的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在servlet中执行JavaScript。是否可以在所有servlet调用中重用相同的Scripting Engine? Servlet实例由多个线程共享。这是否需要为每个请求创建一个新的脚本引擎?这将是一个令人无法接受的性能损失。例如,以下代码是否保存?

I want to execute a JavaScript within a servlet. Is it possible to reuse the same Scripting Engine across all servlet invocations? Servlet instances are shared by multiple threads. Does this require to create a new Scripting Engine per request? That would be a unacceptable performance penalty. As an example, is the following code save?

public class MyServlet extends HttpServlet {

private ScriptEngineManager factory;
private ScriptEngine engine;

@Override
public void init() throws ServletException {
    factory = new ScriptEngineManager();
    engine = factory.getEngineByName("nashorn");
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
        ScriptContext newContext = new SimpleScriptContext();
        newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
        Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
        engineScope.put("writer", writer);
        Object value = engine.eval("writer.print('Hello, World!');", engineScope);
        writer.close();
    } catch (IOException | ScriptException ex) {
        Logger.getLogger(AsyncServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

}

如果这不安全,那么避免每个请求创建引擎的最佳方法是什么?使用引擎池?

If this is not safe, what would be the best way to avoid creating an engine per request? Using a pool of engines?

编辑:
是否可以重复使用同一个引擎和同一个JavaScriptObject,这会导致评估结果一个JS函数,对于所有servlet请求,如果该函数不更改任何共享对象但仅使用调用给出的参数?看看以上示例的以下适应性:

Is it possible to reuse one and the same engine and one and the same JavaScriptObject, which results as the evaluation of a JS-function, for all servlet requests, if the function does not change any shared object but uses only the arguments given with the call? Look at the following adaptaion of the above example:

public class MyServlet extends HttpServlet {

private ScriptEngineManager factory;
private ScriptEngine engine;
private ScriptObjectMirror script;

@Override
public void init() throws ServletException {
    try {
        factory = new ScriptEngineManager();
        engine = factory.getEngineByName("nashorn");
        script = (ScriptObjectMirror)engine.eval("function(writer) {writer.print('Hello, World!');}");
    } catch (ScriptException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
        script.call(null, writer);
        writer.close();
    } catch (IOException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

这样安全吗?

推荐答案

javax.script.ScriptEngineFactory 中有一个方法 getParameter(String key)

In javax.script.ScriptEngineFactory there is a method getParameter(String key).

使用特殊键 THREADING ,您将获得此特定的线程信息发动机工厂。

With the special key THREADING you get threading information for this specific engine factory.

这个小程序为每个注册的发动机工厂打印出这些信息:

This small program prints out this information for every registered engine factory:

import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

public class ScriptEngineTest {
  public static void main(String[] args) {
    final ScriptEngineManager mgr = new ScriptEngineManager();
    for(ScriptEngineFactory fac: mgr.getEngineFactories()) {
      System.out.println(String.format("%s (%s), %s (%s), %s", fac.getEngineName(),
          fac.getEngineVersion(), fac.getLanguageName(),
          fac.getLanguageVersion(), fac.getParameter("THREADING")));
    }
  }
}

对于Java 7,它是:

For Java 7 it is:

Mozilla Rhino (1.7 release 3 PRERELEASE), ECMAScript (1.8), MULTITHREADED

对于Java 8:

Oracle Nashorn (1.8.0_25), ECMAScript (ECMA - 262 Edition 5.1), null

null 表示引擎实现不是线程安全的。

null means the engine implementation is not thread safe.

在你的servlet中你可以使用 ThreadLocal 为每个人保留一个单独的引擎线程允许为同一线程提供的后续请求重用引擎。

In your servlet you can use a ThreadLocal to hold a seperate engine for each thread allowing to reuse the engine for subsequent requests served by the same thread.

public class MyServlet extends HttpServlet {

  private ThreadLocal<ScriptEngine> engineHolder;

  @Override
  public void init() throws ServletException {
    engineHolder = new ThreadLocal<ScriptEngine>() {
      @Override
      protected ScriptEngine initialValue() {
        return new ScriptEngineManager().getEngineByName("nashorn");
      }
    };
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
      ScriptContext newContext = new SimpleScriptContext();
      newContext.setBindings(engineHolder.get().createBindings(), ScriptContext.ENGINE_SCOPE);
      Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
      engineScope.put("writer", writer);
      Object value = engineHolder.get().eval("writer.print('Hello, World!');", engineScope);
      writer.close();
    } catch (IOException | ScriptException ex) {
      Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
}

这篇关于在Servlet中重用Nashorn ScriptEngine的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆