java 脚本引擎

本文节选自《Netkiller Java 手札》

第 18 章 java 脚本引擎

目录

  • 18.1. Maven
  • 18.2. Helloworld
  • 18.3. 运行脚本文件
  • 18.4. 变量传递
  • 18.5. 全局变量与局部变量定义
  • 18.6. 调用脚本中的函数或方法
  • 18.7. 脚本编译

什么是脚本引擎,脚本引擎是指在程序运行期间嵌入另一种脚本语言,并与其交互,产生最终运行结果

脚本引擎存在的意义是什么?脚本引擎可以改变编译语言的内部运行逻辑,弥补编译语言的不足,使编译语言具备动态语言的一部分特性。

是否有成功案例?最成功的案例就是基于C++和Lua语言开发的端游(网游一种,需要按照客户端),编译语言最大的缺点就是客户端升级需要重新安装并且安装之后重启应用程序才能生效。脚本引擎弥补了这项致命的缺点,用户只需升级剧情脚本,而不需要退出整个游戏然后重新进入。

18.1. Maven

		<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.netkiller</groupId>
	<artifactId>script</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>Java Script</name>
	<description>Java Script Engine</description>
	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-all</artifactId>
			<version>1.10.19</version>
		</dependency>
	</dependencies>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

18.2. Helloworld

		package javascript;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Helloworld {

	public Helloworld() {
		ScriptEngineManager manager = new ScriptEngineManager();
		List<ScriptEngineFactory> factories = manager.getEngineFactories();
		for (ScriptEngineFactory f : factories) {
			System.out.println("egine name:" + f.getEngineName());
			System.out.println("engine version:" + f.getEngineVersion());
			System.out.println("language name:" + f.getLanguageName());
			System.out.println("language version:" + f.getLanguageVersion());
			System.out.println("names:" + f.getNames());
			System.out.println("mime:" + f.getMimeTypes());
			System.out.println("extension:" + f.getExtensions());
			System.out.println("-----------------------------------------------");
		}
	}

	public void hello() throws ScriptException {
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("JavaScript");
		// ScriptEngine engine = manager.getEngineByExtension("js");
		// ScriptEngine engine = manager.getEngineByMimeType("text/javascript");
		engine.eval("print('Hello, World')");
	}

	public static void main(String[] args) {
		try {
			new Helloworld().hello();
		} catch (ScriptException ex) {
			Logger.getLogger(Helloworld.class.getName()).log(Level.SEVERE, null, ex);
		}
	}
}

18.3. 运行脚本文件

将脚本放入外部文件

		package javascript;

import java.io.FileNotFoundException;
import java.net.URL;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class EvalFile {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByExtension("js");
		// ScriptEngine engine = manager.getEngineByMimeType("text/javascript");

		try {

			URL location = EvalFile.class.getProtectionDomain().getCodeSource().getLocation();
			String file = location.getFile() + "test.js";
			System.out.println(file);

			engine.eval(new java.io.FileReader(file));

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}		

test.js

print("This is hello from test.js");		

18.4. 变量传递

		package javascript;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class ScriptVars {

	ScriptEngine engine = null;

	public ScriptVars() {
		ScriptEngineManager manager = new ScriptEngineManager();
		engine = manager.getEngineByMimeType("text/javascript");
	}

	public void variable() throws ScriptException {
		engine.put("name", "Neo");
		engine.eval("var message = 'Hello, ' + name;");
		engine.eval("print(message);");
		Object obj = engine.get("message");
		System.out.println(obj);
	}

	public void simpleBindings() throws ScriptException {
		Bindings bindings = new SimpleBindings();
		bindings.put("name", "Neo");
		engine.eval("print('I am ' + name);", bindings);
	}

	public void function() throws ScriptException {
		engine.put("a", 4);
		engine.put("b", 6);
		Object maxNum = engine.eval("function max_num(a,b){return (a>b)?a:b;}max_num(a,b);");
		System.out.println("max_num:" + maxNum + ", (class = " + maxNum.getClass() + ")");

		Map<String, Integer> m = new HashMap<String, Integer>();
		m.put("c", 10);
		engine.put("m", m);
		engine.eval("var x= max_num(a,m.get('c'));");
		System.out.println("max_num:" + engine.get("x"));
	}

	public void object() throws ScriptException {
		File f = new File("test.txt");
		// expose File object as variable to script
		engine.put("file", f);

		// evaluate a script string. The script accesses "file"
		// variable and calls method on it
		engine.eval("print(file.getAbsolutePath())");
	}

	public void outputToFile() throws IOException, ScriptException {
		ScriptContext context = engine.getContext();
		context.setWriter(new FileWriter("script.log"));
		engine.eval("print('Hello World!');");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		try {
			ScriptVars sv = new ScriptVars();
			sv.variable();
			sv.simpleBindings();
			sv.outputToFile();
			sv.function();
			sv.object();
			sv.outputToFile();

		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

18.5. 全局变量与局部变量定义

ScriptContext.GLOBAL_SCOPE 作用于 ScriptEngineManager, ScriptContext.ENGINE_SCOPE 作用于 ScriptEngine

		package javascript;

import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ContextVariable {

	public static void main(String[] args) throws ScriptException {
		// TODO Auto-generated method stub
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("JavaScript");
		ScriptContext context = engine.getContext();  
	    context.setAttribute("name", "Netkiller", ScriptContext.GLOBAL_SCOPE);  
	    context.setAttribute("name", "Neo", ScriptContext.ENGINE_SCOPE);  
	    //context.getAttribute("name"); 
	    engine.eval("print('I am ' + name);", context);
	    
	    // engine1,context1 并没有定义 name 但输出结果却显示 Netkiller,所以ScriptContext.GLOBAL_SCOPE定义的变量是全局的。 
	    ScriptEngine engine1 = manager.getEngineByName("JavaScript");
	    ScriptContext context1 = engine1.getContext();  
	    engine.eval("print('I am ' + name);", context1);
	    
	}

}		

18.6. 调用脚本中的函数或方法

		package javascript;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class InvokeScriptFunction {

	public static void main(String[] args) throws ScriptException, NoSuchMethodException {
		// TODO Auto-generated method stub
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("JavaScript");

		// JavaScript code in a String
		String script = "function hello(name) { print('Hello, ' + name); }";
		// evaluate script
		engine.eval(script);

		// javax.script.Invocable is an optional interface.
		// Check whether your script engine implements or not!
		// Note that the JavaScript engine implements Invocable interface.
		Invocable inv = (Invocable) engine;

		// invoke the global function named "hello"
		inv.invokeFunction("hello", "Scripting!!");

		// JavaScript code in a String. This code defines a script object 'obj'
		// with one method called 'hello'.
		script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
		// evaluate script
		engine.eval(script);
		// get script object on which we want to call the method
		Object obj = engine.get("obj");

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

18.7. 脚本编译

只有重复执行脚本时才需要编译。只运行一次不建议编译运行。

		package javascript;

import javax.script.*;

public class ScriptCompile {
	public CompiledScript compile(String script) throws ScriptException {

		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("JavaScript");

		return ((Compilable) engine).compile(script);

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ScriptCompile sc = new ScriptCompile();
		try {

			CompiledScript script = sc.compile("print('Helloworld!!!');");

			for (int i = 0; i < 100; i++) {
				script.eval();
			}

		} catch (ScriptException ex) {
			ex.printStackTrace();
		}
	}

}		

原文发布于微信公众号 - Netkiller(netkiller-ebook)

原文发表时间:2016-09-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏欧阳大哥的轮子

手把手教你查看和分析iOS的crash崩溃异常

一个应用程序并不总会一直运行的很好,它总会有出现crash崩溃的情况。如果在应用程序中接入了一些第三方的crash收集工具或者自建crash收集报告平台的话将会...

1262
来自专栏逆向技术

异常处理第二讲,结构化异常(微软未公开)

            异常处理第二讲,结构化异常(微软未公开) 讲解之前,请熟悉WinDbg的使用,工具使用的博客链接 一丶认识段寄存器FS的内容,以及作用 ...

1867
来自专栏老马说编程

(64) 常见文件类型处理: 属性文件/CSV/EXCEL/HTML/压缩文件 / 计算机程序的思维逻辑

查看历史文章,请点击上方链接关注公众号。 对于处理文件,我们介绍了流的方式,57节介绍了字节流,58节介绍了字符流,同时,也介绍了比较底层的操作文件的方式,60...

3068
来自专栏FreeBuf

如何在32位系统中使用ROP+Return-to-dl来绕过ASLR+DEP

传统的利用return-to-plt+ROP来绕过ASLR + DEP的技术需要知道库中函数的偏移地址,而在没有libc库的情况下可以使用Return-to-d...

2827
来自专栏琯琯博客

Yii2 学习笔记之验证规则

3266
来自专栏阮一峰的网络日志

浏览器加载 CommonJS 模块的原理与实现

就在这个周末,npm 超过了 cpan ,成为地球上最大的软件模块仓库。 npm 的模块都是 JavaScript 语言写的,但浏览器用不了,因为不支持 Com...

3498
来自专栏从零开始学自动化测试

Selenium2+python自动化58-读取Excel数据(xlrd)

前言 当登录的账号有多个的时候,我们一般用excel存放测试数据,本节课介绍,python读取excel方法,并保存为字典格式。 一、环境准备 1.先安装...

2726
来自专栏炉边夜话

JNI使用技巧点滴

本文为在 32 位 Windows 平台上实现 Java 本地方法提供了实用的示例、步骤和准则。本文中的示例使用 Sun Microsystems 公司创建的 ...

431
来自专栏图形学与OpenGL

实验3 文件操作

    (3)     根据这个随机数,从所读取的记录中找到对应的记录,并输出显示;

842
来自专栏Java帮帮-微信公众号-技术文章全总结

Java web图片上传和文件上传

图片上传和文件上传本质上是一样的,图片本身也是文件。文件上传就是将图片上传到服务器,方式虽然有很多,但底层的实现都是文件的读写操作。 注意事项 1.form表单...

3767

扫码关注云+社区