欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 【script】java武魂技展示:在java中使用不同的脚本语言 一文体现java生态的强大

【script】java武魂技展示:在java中使用不同的脚本语言 一文体现java生态的强大

2024/10/25 11:20:46 来源:https://blog.csdn.net/qq_36268103/article/details/142376698  浏览:    关键词:【script】java武魂技展示:在java中使用不同的脚本语言 一文体现java生态的强大

我们经常听到java强大在于它的生态,对于生态的理解我们一般可能想到的是spring家族、微服务那一套中间件;其实java生态的强大也体现在它能使用各种脚本语言,博主最近在项目中考虑使用脚本语言以达到动态效果,因此顺带例举了常用的脚本语言方式

文章目录

  • java中使用js
  • java中使用python
  • java中使用lua
  • java中使用groovy
  • 混合使用效果展示

java中使用js

在旧版本的jdk(8-14)中 默认是带有js引擎的,使用较为通用的方式即可:

  		// 该方式在jdk15已经不可用 被移除了 Nashorn , 在jdk15之前 默认是通过Nashorn来作为JavaScriptEngine的ScriptEngineManager MANAGER = new ScriptEngineManager();// JavaScriptEngine  获取一个JavaScript引擎 (脚本语言本质是实现ScriptEngine接口)ScriptEngine engine = MANAGER.getEngineByName("js");// 定义JavaScript代码script = "var a = 1; var b = 2; a + b;";try {// 执行JavaScript代码Object result = engine.eval(script);// jdk >=15 engine is nullSystem.out.println(result);} catch (Exception e) {e.printStackTrace();}

本文不再介绍低版本jdk使用方式,以下所有代码皆基于jdk21环境举例:

     // 使用js方式try (Context context = Context.create()) {Value result = context.eval("js", "var a = 1; var b = 2; a + b;");System.out.println(result.asInt());// 3return result.toString();}
        <!-- js 支持--><dependency><groupId>org.graalvm.js</groupId><artifactId>js</artifactId><version>21.0.0</version></dependency>

java中使用python

    public String test(String script) {// Jython 只支持 Python 2 语法,且无法调用用 C 扩展编写的 Python 模块(例如一些涉及原生代码的库)。// 其它方式不受python版本限制的方式:  1.ProcessBuilder  需要安装了python 并配置环境变量// 2. GraalVM 虚拟机(支持多语言) 这种方式需要你使用 GraalVM 作为运行环境,并安装 Python 语言支持PythonInterpreter interpreter = new PythonInterpreter();interpreter.exec("print('原创作者csdn:孟秋与你')");// 执行带参数的 Python 脚本interpreter.set("javaVar", new PyInteger(42));interpreter.exec("pythonVar = javaVar * 2");PyObject result = interpreter.get("pythonVar");return result.toString();}
        <!-- python 2支持--><dependency><groupId>org.python</groupId><artifactId>jython-standalone</artifactId><version>2.7.2</version></dependency>

java中使用lua

我们经常在redis中使用lua脚本 达到分布式锁的效果 例如redisson组件也是通过lua脚本写的

  1. redis使用lua脚本
/*** @author csdn:孟秋与你 /github:qiuhuanhen*/
@Configuration
public class LuaScriptConfig {@Beanpublic RedisScript<String> script() {DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();// resource目录下创建的scripts文件夹redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/xxx.lua")));redisScript.setResultType(String.class);return redisScript;}@Beanpublic RedisTemplate<String, Object> luaRedisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);// 设置 key 和 value 的序列化方式为 StringStringRedisSerializer stringRedisSerializer = new StringRedisSerializer();template.setKeySerializer(stringRedisSerializer);template.setValueSerializer(stringRedisSerializer);template.setHashKeySerializer(stringRedisSerializer);template.setHashValueSerializer(stringRedisSerializer);template.afterPropertiesSet();return template;}
}

@RequestMapping("/redis")
@RestController
public class RedisIdController {@Autowiredprivate LuaRedisTemplateluaRedisTemplate;@Autowiredprivate RedisScript<String> script;@GetMappingpublic String test() {// 取决你的脚本需要几个传参return luaRedisTemplate.execute(script, java.util.List.of("param1", "param2"....));}
}

lua示例

-- 获取自增ID KEYS[1]对应上文param1
local increment = redis.call("INCR", KEYS[1])
       <!-- Spring Data Redis version和springboot版本一致 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
  1. 纯java中使用lua脚本

使用lua脚本相比其它脚本语言 有一个优势在于权限可控,可以通过控制load的模块,极大的限制lua脚本能做的事情;换句话说,当我们把脚本能力开放给维护人员或内部系统接口时,风险也是可控的,不至于被删库跑路。

一般标准下是使用JsePlatform.standardGlobals(); 这个权限还是很危险的,所以我们可以选择基础功能load即可,具体看下面注释:

本文原创作者:csdn 孟秋与你

import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.Bit32Lib;
import org.luaj.vm2.lib.CoroutineLib;
import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
import org.luaj.vm2.lib.jse.JseBaseLib;
import org.luaj.vm2.lib.jse.JseIoLib;
import org.luaj.vm2.lib.jse.JseMathLib;
import org.luaj.vm2.lib.jse.JseOsLib;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.lib.jse.LuajavaLib;
import org.springframework.stereotype.Component;@Component
public class LuaConfig {private Globals globals;public LuaConfig() {// 使用标准 JSE 环境创建 Lua 环境 (包含标准库,不注入自定义的Java 对象)
//        this.globals = JsePlatform.standardGlobals();// 从标准库的源码中,筛选最最基本的功能(降低风险)globals = new Globals();// 基本函数 print() error()等globals.load(new JseBaseLib());// 管理 Lua 模块和包,除了JseBaseLib 其它基础模块要用到。允许通过该require()函数加载外部 Lua 模块。globals.load(new PackageLib());// 提供用于操作整数的按位运算。globals.load(new Bit32Lib());// 提供操作Lua表(数组、字典)的函数。globals.load(new TableLib());// 提供字符串操作功能。globals.load(new StringLib());// 允许使用协同程序(轻量级线程)
//        globals.load(new CoroutineLib());// 提供常见的数学函数,如、、sin()等。cos()random()globals.load(new JseMathLib());// 提供文件输入/输出(I/O)操作的功能。
//        globals.load(new JseIoLib());// 提供与操作系统相关的功能,如获取环境变量、执行shell命令等。
//        globals.load(new JseOsLib());// 提供从 Lua 脚本与 Java 对象交互的能力 (LuajavaLib 允许 Lua 脚本直接访问 Java 对象、类、甚至 Java 运行时环境)
//        globals.load(new LuajavaLib());// 禁用path cpath (加载外部脚本)
//        globals.get("package").set("path", LuaValue.valueOf(""));
//        globals.get("package").set("cpath", LuaValue.valueOf(""));// 禁用 require 函数 将外部脚本作为模块导入 (这是个辅助功能,require导入的脚本 依然不能使用globals没load的模块功能 但可能导入外部复杂的脚本)
//        globals.set("require", LuaValue.NIL);LoadState.install(globals);LuaC.install(globals);// 手动注入java对象方式
//        LuaValue controller = CoerceJavaToLua.coerce(new LuaController());
//        this.globals.set("controller", controller);
//        this.globals.set("key", "原创作者 csdn:孟秋与你");}public LuaValue executeLuaScript(String script) {// 加载并执行 Lua 脚本LuaValue chunk = globals.load(script);return chunk.call();}public Globals getGlobals() {return globals;}}
     <!--lua支持--><dependency><groupId>org.luaj</groupId><artifactId>luaj-jse</artifactId><version>3.0.1</version></dependency>

java中使用groovy

    public String test(Long id) {GroovyShell shell = new GroovyShell();// 语言特性:自动返回最后一个值  即使是个固定值也会返回Script script1 = shell.parse("def temp = binding.variables.get(\"id\") as Long \n \"一个固定值-本文原创作者:csdn孟秋与你\"\n");// 一个固定值return String.valueOf(script1.run());}
       <!-- groovy 支持--><dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy</artifactId><version>3.0.17</version></dependency>

混合使用效果展示

如果将上述脚本混合使用,将会看到一个java的武魂组合技:


/*** 不同脚本语言混合演示*/
@RequestMapping("/test/script")
@RestController
public class ScriptController {/**  这是上文lua部分的LuaConfig配置  **/@Autowiredprivate LuaConfig luaConfig;@GetMappingpublic String test() {// jstry (Context context = Context.create()) {Value result = context.eval("js", "var a = 333; var b = 333; a + b;");System.out.println("js: " + result.asInt());}// luaLuaValue luaValue = luaConfig.executeLuaScript("local res = 666 return tostring(res)");System.out.println("lua: " + luaValue.toString());// groovyScript groovy = new GroovyShell().parse(" def groovy = \"csdn的 孟秋与你 是世界上最好的博主 以及groovy是世界上最好的语言.class\"");System.out.println("groovy: " + groovy.run());// pythonPythonInterpreter interpreter = new PythonInterpreter();interpreter.exec("res = \"**  python\"");PyObject result = interpreter.get("res");System.out.println("python: " + result.toString());return "java";}
}

运行展示:

在这里插入图片描述

tips: 这回真的 groovy是世界上最好的语言.class,不是玩梗 groovy是生成字节码 运行在jvm的脚本语言

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com