在Servlet中重用Nashorn ScriptEngine

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

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);

}

}

}

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

是否可以对所有Servlet请求重用一个同一个引擎和一个同一个JavaScriptObject,作为对JS函数的求值,如果该函数不更改任何共享对象而仅使用给定的参数跟电话吗?查看上面示例的以下适应:

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)

使用特殊键,THREADING您可以获得该特定引擎工厂的线程信息。

这个小程序为每个注册的引擎工厂打印出此信息:

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,它是:

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 表示引擎实现不是线程安全的。

在您的Servlet中,您可以使用ThreadLocal来为每个线程保留一个单独的引擎,从而允许将引擎重新用于同一线程所服务的后续请求。

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 的全部内容, 来源链接: utcz.com/qa/414560.html

回到顶部