【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的脚本语言

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/146201.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

prometheus通过nginx-vts-exporter监控nginx

Prometheus监控nginx有两种方式。 一种是通过nginx-exporter监控&#xff0c;需要开启nginx_stub_status,主要是nginx自身的status信息&#xff0c;metrics数据相对较少&#xff1b; 另一种是使用nginx-vts-exporter监控&#xff0c;但是需要在编译nginx的时候添加nginx-module…

Vuex 入门与实战

引言 Vuex 是 Vue.js 官方推荐的状态管理库&#xff0c;它可以帮助我们更好地管理 Vue 应用的状态。在大型应用中&#xff0c;组件之间的状态共享和通信是一个非常重要的问题&#xff0c;而 Vuex 提供了一种优雅的解决方案。 在 Vue 应用中&#xff0c;数据的流动一般是单向的…

Android Perfetto 学习

1、如何抓取性能日志 方式1、通过手机里的System Tracing抓取 1、点击Settings->System->Developer options->System Tracing->Record trace 打开 2、操作完成后&#xff0c;点击Settings->System->Developer options->System Tracing->Record trace…

初始泛型【超级详细哦~】

初始泛型【超级详细哦~】 1、包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和拆箱 2、泛型2.1 什么是泛型2.2 泛型的语法2.3泛型的使用2.4 泛型的上界2.4.1 语法2.4.2 示例 1、包装类 1.1 基本数据类型和对应的包装类 1.2 装箱和拆箱 int i10;//装箱操作&a…

PCL 点云圆柱邻域搜索

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#xff09; 一、概述 本文将介绍如何使用PCL库进…

【白皮书下载】分布式功能安全的创新与突破

近日&#xff0c;Imagination 推出全新性能最高且具有高等级功能安全性的汽车 GPU IP——Imagination DXS GPU&#xff0c;并且是Imagination 第一款带有“分布式安全机制”的处理器。 下载白皮书&#xff0c;获取完整分布式安全机制解决方案 根据 ISO 26262 汽车安全完整性等级…

11.1图像的腐蚀和膨胀

基本概念-图像腐蚀 图像腐蚀是一种用于去除图像中小的对象或者突出物体边缘的形态学操作。 图像腐蚀&#xff08;erosion&#xff09;的基本概念 图像腐蚀通常用于二值图像&#xff0c;其基本原理是从图像中“侵蚀”掉一些像素点&#xff0c;这些像素点通常是边界上的或者是孤…

【有啥问啥】OpenAI o1的思考之前训练扩展定律、后训练扩展定律与推理扩展定律:原理与应用详解

OpenAI o1的思考之前训练扩展定律、后训练扩展定律与推理扩展定律&#xff1a;原理与应用详解 随着深度学习技术的不断发展&#xff0c;模型的规模和复杂度也迅速提升。研究人员发现了模型训练和推理过程中性能变化的规律&#xff0c;这些规律为我们提供了优化模型设计与训练的…

BGP 路由反射器

转载&#xff1a;BGP 路由反射器 / 实验介绍: / 原理概述 缺省情况下&#xff0c;路由器从它的一个 IBGP 对等体那里接收到的路由条目不会被该路由器再传递给其他IBGP对等体&#xff0c;这个原则称为BGP水平分割 原则&#xff0c;该原则的根本作用是防止 AS 内部的 BGP 路由…

linux入门——“linux基本指令”下

1.mv指令 mv指令用于移动文件或者目录。语法是mv 源文件 目标文件。它的用法需要注意&#xff1a; 当目标文件不存在的时候&#xff0c;默认是将源文件进行重命名操作&#xff0c;名字就是目标文件的名字&#xff0c;当目标文件存在的时候才会把源文件移动到目标文件。 目标文…

微服务远程调用(nacos及OpenFeign简单使用)

问题&#xff1a;在微服务中&#xff0c;每个项目是隔离开的&#xff0c;当有一个项目请求其他项目中的数据时&#xff0c;必须发起网络请求&#xff0c;本文即对此问题展开讨论。 1.使用restTemplate发送请求 //发送请求ResponseEntity<List<ItemDTO>> response …

Microsoft 365 Copilot: Wave 2 发布,开启AI时代下的全新工作流

本周一&#xff08;9月16日&#xff09;&#xff0c;微软对 Microsoft 365 Copilot 办公辅助工具进行了重大升级&#xff0c;推出 Wave 2 版本。新版 Copilot 将为 Microsoft 365 用户带来一系列新功能和改进&#xff0c;进一步提升工作效率与用户体验&#xff0c;正式开启AI时…

【machine learning-13-线性回归的向量化】

向量化 向量化简洁并行计算 向量化 线性回归的向量化表示如下&#xff0c;其中w 和 x 都分别加了箭头表示这是个向量&#xff0c;后续不加也可以表示为向量&#xff0c;w和x点乘加上b&#xff0c;就构成了多元线性回归的表达方式&#xff0c;如下&#xff1a; 那么究竟为什么…

uniapp|微信小程序 实现输入四位数 空格隔开

<template><page-meta :page-style"cssVar"></page-meta><view class"container"><u-navbartitle"优惠券兑换"placeholderbgColor"#fff":autoBack"true":titleStyle"{fontFamily: SourceHa…

navicat无法连接远程mysql数据库1130报错的解决方法

出现报错&#xff1a;1130 - Host ipaddress is not allowed to connect to this MySQL serve navicat&#xff0c;当前ip不允许连接到这个MySQL服务 解决当前ip无法连接远程mysql的方法 1. 查看mysql端口&#xff0c;并在服务器安全组中放开相应入方向端口后重启服务器 sud…

MySQL篇(存储引擎 - InnoDB存储引擎架构)(持续更新迭代)

目录 一、逻辑存储结构 1. 表空间 2. 段 3. 区 4. 页 5. 行 二、架构 1. 简介 2. 内存结构&#xff08;四部分&#xff09; Buffer Pool Change Buffer Adaptive Hash Index Log Buffer 3. 磁盘结构&#xff08;七部分&#xff09; System Tablespace File-Per-…

【工具变量】科技金融试点城市DID数据集(2000-2023年)

时间跨度&#xff1a;2000-2023年数据范围&#xff1a;286个地级市包含指标&#xff1a; year city treat post DID&#xff08;treat*post&#xff09; 样例数据&#xff1a; 包含内容&#xff1a; 全部内容下载链接&#xff1a; 参考文献-pdf格式&#xff1a;https://…

大觅网之环境部署(Environment Deployment of Da Mi Network)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

World of Warcraft [CLASSIC] International translation bug

internationalization i18n_getinternationalizationjs-CSDN博客 1&#xff09;国际化翻译不完整 Chance on melee and ranged critical strike to increase your attack power by 1262 for 10s. 2&#xff09;更新美酒节&#xff0c;服务器并发太高&#xff0c;被提出副本 Wo…

[Redis][String][下]详细讲解

目录 1.其他命令1.APPEND2.GETRANGE3.SETRANGE4.STRLEN 2.内部编码3.典型使用场景1.缓存(Cache)功能2.计数(Counter)功能3.共享会话(Session) 1.其他命令 1.APPEND 功能&#xff1a; 如果key已经存在并且是⼀个string&#xff0c;命令会将value追加到原有string的后边如果key…