游戏项目中都会遇到以下的一些需求:
1.从内存里查询数据
2.修复个别玩家的异常数据
如何能最快捷的方式去实现,目前有两种脚本引擎可以选择:beanshell 和groovy.
经过比较得出如下结论:
BeanShell | Groovy | |
官网 | BeanShell - Lightweight Scripting for Java | The Apache Groovy programming language |
介绍 | 用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k | 是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库。 |
执行原理 | 使用Java反射API以提供Java语句和表达式 的实时解释执行;可以透明地访问任何Java对象和API。 | 动态地加载一个脚本并执行它的行为。GroovyClassLoader是一个定制的类装载器,负责解释加载Java类中用到的Groovy类 |
直接访问私有方法 | 可以 | 可以 |
泛型 | 不支持 | 支持 |
评价 | 专注,小而强大,小强 | 沉睡的巨人 |
脚本量 | 少 | 除了目标脚本外面要套一层类的外壳 |
语言友好性 | 纯java语言 | 纯java语言 |
后遗症 | 没有 | Groovy每执行一次脚本,都会生成一个脚本对应的class对象存放metaspace, 但可以通过每次new GroovyClassLoader或者调用GroovyClassLoader.clearCache()去化解 |
性能 | 非常快 | GroovyShell执行groovy语言,静态编译情况下速度还可以, GroovyClassLoader 要相对Beanshell要慢一些 |
IDE对引擎的支持 | 无 | 更友好,高亮,语法智能插入 |
社区 | 不大活跃,目前在谋划beanshell3 |
BeanShell使用:
script.bsh脚本
import io.gamioo.script.ScriptManager; for(int i=0;i<10;i++){ String content="hello world"; ScriptManager.getInstance().log(content); }
beanshell执行脚本:
public void init() throws ServiceException { logger.info("开始初始化Java Script引擎."); // 让所有的非public方法和字段可供调用 try { Capabilities.setAccessibility(true); } catch (Unavailable e) { throw new ServiceException(e); } logger.info("成功初始化Java Script引擎."); } public String execScriptByBeanshell(String script) { try { Object output = interpreter.eval(script); return output == null ? "OK" : output.toString(); } catch (TargetError e) { Throwable able = e.getTarget(); logger.error(e.getMessage(), e); return able.toString(); } catch (Exception e) { logger.error(e.getMessage(), e); return e.getMessage(); } }
Groovy 使用:
script.groovy脚本:
package io.gamioo.script public class GroovyScriptExecutor2 implements GroovyScript { @Override public String execute() { for(int i=0;i<10;i++){ String content="hello world"; ScriptManager.getInstance().log("Hello ketty"); } return "OK"; } }
groovy执行脚本:
/** * Groovy脚本接口. */ public interface GroovyScript { /** * 执行逻辑. * * @return 执行结果 */ public String execute(); } /** * 执行一段Groovy脚本. * * @param script Groovy脚本 * @return 执行结果 */ public String executeByGroovy(String script) { try (GroovyClassLoader loader = new GroovyClassLoader()) { // loader.clearCache(); return ((GroovyScript) loader.parseClass(script).newInstance()).execute(); } catch (Exception e) { logger.error("groovy script execute exception.{}", e); return ExceptionUtils.toString(e); } }
测试类:
@DisplayName("脚本测试") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ScriptManagerTest { private static final Logger logger = LogManager.getLogger(ScriptManagerTest.class); private static ScriptManager scriptManager; @BeforeAll public static void beforeAll() throws Exception { scriptManager=ScriptManager.getInstance(); scriptManager.init(); } @Test @DisplayName("BeanShell脚本测试") public void testBeanShell() throws Exception { File file= FileUtils.getFile("script.bsh"); String content=FileUtils.readFileToString(file); scriptManager.execScriptByBeanshell(content); } @Test @DisplayName("Groovy脚本测试") public void testGroovyClassLoader() throws Exception { File file=FileUtils.getFile("script.groovy"); String content=FileUtils.readFileToString(file); scriptManager.executeByGroovy(content); } }
后台脚本系统UI设计
参考:
java groovy集成_Groovy与Java集成常见的坑
Java ImportCustomizer.addStarImports方法代码示例
这篇文章可以研究下有些单例的,已经在容器里的可以不用再import的问题