我想这种脚本调用具有可读性,并且这种调用方式对java开发人员来说不会陌生。
这些是想法,并且用这些想法来基于 Spring Framework 创建脚本仓库的实现库。这个库包含从不同来源加载并执行脚本的基础设施,同时也提供了一些API, 开发人员可以使用这些API对这个库进行扩展。
它如何工作
这个库创建了一些注解(以及XML配置,有的开发人员可能偏好于使用XML配置),在上下文初始化期间,为使用@ScriptRepository注解的所有Repository接口初始化动态代理。这些代理发布为实现Repository接口的单例bean,这意味着可以使用@Autowired或@Inject将这些代理注入到bean中,如上一节中的代码片段所示。
在其中一个应用程序的配置类上使用@EnableScriptRepositories注解来激活脚本Repositories。这种方法类似于开发人员熟知的其它Spring 注解(如 @EnableJpaRepositories 或 @EnableMongoRepositories)。对于此注解,需要指定应与 JPA repository相似的扫描包名数组。
如前面所示,我们需要使用 @ScriptMethod 注解来标记脚本Repository中的每个方法(库也提供 @GroovyScript 和 @JavaScript),为方法调用添加元数据并注明这些方法是脚本方法。当然,也支持脚本方法的默认实现。这个解决方案的所有组件都显示在下图中。蓝色图形与应用程序代码相关,白色图形与库相关。Spring bean 有 Spring Logo 。
当调用接口的脚本方法时,它会被代理类拦截,代理类会查找两个 bean - 一个是用于获取实现脚本内容的provider,另一个是用于获取执行结果的evaluator。在脚本执行之后,结果将返回给脚本的调用方。可以用 @ScriptMethod 注解属性指定provider和evaluator以及执行超时(这个库也为这些属性提供了默认值):
你可能会注意到 @ScriptParam 注解 - 我们使用它们为方法的参数提供名称,这些名称应该用在脚本中,因为 Java 编译器会在编译时删除实际的参数名称。也可以不用这个注解,此时,需要以 “arg0”、“arg1” 等来命名脚本参数,只是这会影响代码的可读性。
默认情况下,这个库提供可以从文件系统读取 groovy 和 javascript 文件的provider以及用于两种脚本语言的基于JSR-233 的 evaluator。可以为不同的脚本存储和执行引擎创建自定义的provider和evaluator。所有这些设施都基于 Spring 框架接口(org.springframework.scripting.ScriptSource 和 org.springframework.scripting.ScriptEvaluator),因此可以复用所有基于 Spring 的类。例如,使用StandardScriptEvaluator代替默认的类。
Provider(以及evaluator)会作为 Spring bean 发布,为了提高灵活性,脚本repository代理会按名称解析 - 可以在不更改应用程序代码的情况下将默认执行程序替换为另外一个,只是在应用程序上下文中替换一个 bean。
测试和版本控制
由于脚本很容易更改,因此我们需要确保在改变脚本时不会破坏生产服务器。这个库与 JUnit 测试框架兼容,这里没有特殊之处。由于在基于 Spring 的应用程序中使用这个库,因此在将脚本更新到生产环境之前,可以使用单元测试和集成测试将脚本作为应用程序的一部分来测试,测试中也支持模拟(mocking)框架。
此外,可以创建一个脚本provider,从数据库甚至从 Git 或其它源代码控制系统读取不同版本的脚本文本。在这种情况下,如果生产环境中出现问题,可以很容易切换到新版本的脚本或回滚到之前版本的脚本。
结论
这个库有助于在代码中使用脚本,提供以下功能:
通过引入 java 接口,开发人员可以获取到脚本参数及其类型信息。
Provider和evaluator可以避免分散在饮用程序各处的脚本引擎调用。