java调用Groovy动态代码

感谢作者:https://www.ab62.cn/article/36028.html

我的使用

场景:参数转换(适配上下游)

public static void main(String[] args) {String scriptText = script();GroovyClassLoader classLoader = new GroovyClassLoader();Class groovyClass = classLoader.parseClass(scriptText);try {GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();Object[] param = new Object[]{"{\"skuId\":\"835578\"}"};Object convert = groovyObject.invokeMethod("convert", param);System.out.println(JSON.toJSONString(convert));}catch (Exception e) {e.printStackTrace();}}private static String script() {return "package com.yonghui.yh.open.vop.adapt.service.convertor.groovy;\n" +"\n" +"import com.alibaba.fastjson.JSON;\n" +"import com.jd.open.api.sdk.request.vopsp.VopGoodsGetSkuDetailInfoRequest;\n" +"import com.yonghui.yh.open.vop.adapt.service.convertor.groovy.ConvertInterface;\n" +"\n" +"public class Converter implements ConvertInterface {\n" +"    public String convert(String... manStr) {\n" +"        //消息查询\n" +"        VopGoodsGetSkuDetailInfoRequest request = new VopGoodsGetSkuDetailInfoRequest();\n" +"        //上游传入的参数\n" +"        ReqVopGoodsGetSkuDetailInfo req = JSON.parseObject(manStr[0], ReqVopGoodsGetSkuDetailInfo.class);\n" +"        request.setSkuId(req.getSkuId());\n" +"        request.setQueryExtSet(req.getQueryExtSet());\n" +"        return JSON.toJSONString(request);\n" +"    }\n" +"\n" +"    //上游传入的商品信息\n" +"    static class ReqVopGoodsGetSkuDetailInfo {\n" +"        private long skuId;\n" +"        private String queryExtSet;\n" +"\n" +"        public long getSkuId() {\n" +"            return skuId;\n" +"        }\n" +"\n" +"        public void setSkuId(long skuId) {\n" +"            this.skuId = skuId;\n" +"        }\n" +"\n" +"        public String getQueryExtSet() {\n" +"            return queryExtSet;\n" +"        }\n" +"\n" +"        public void setQueryExtSet(String queryExtSet) {\n" +"            this.queryExtSet = queryExtSet;\n" +"        }\n" +"    }\n" +"}\n" +"\n";}
@Slf4j
@Service
public class GroovyConvert {private static final Map<String, List<TupleTwo<Integer, Object>>> SCRIPT_MAP = Maps.newConcurrentMap();@Autowiredprivate GroovyShell groovyShell;/***  脚本转换,脚本中有RRException 抛出RRException异常,其他转换异常返回原始参数**/public String dynamicConvert(VopParamTypeEnum vopParamTypeEnum, String relationApiKey, String scriptContent, int maxscriptCont, String... paramStr) throws RRException {if (StringUtils.isBlank(relationApiKey) || StringUtils.isBlank(scriptContent) || paramStr == null || paramStr.length == 0) {return null;}String localCacheKey = relationApiKey+"_"+vopParamTypeEnum.getKey();try {Object converter = getExecutorByScript(localCacheKey, scriptContent, maxscriptCont);Class clazz = converter.getClass();Object[] args = new Object[]{paramStr};Class[] argsClass = new Class[args.length];for (int i = 0; i < args.length; i++) {argsClass[i] = args[i].getClass();}Method method = clazz.getMethod("convert", argsClass);method.setAccessible(true);String invokeResult = (String) method.invoke(converter, args);return invokeResult;} catch (InvocationTargetException e) {log.error("脚本异常", scriptContent, e);if (e.getCause() instanceof RRException) {RRException rrException = (RRException) e.getCause();throw new RRException(rrException.getCode(), rrException.getMessage());}} catch (Exception e) {log.error("脚本转换错误,script={},param={}", scriptContent, e);}return paramStr[0];}private Object getExecutorByScript(String localCacheKey, String scriptContent, int maxscriptCont) throws Exception {List<TupleTwo<Integer, Object>> tupleTwoList = SCRIPT_MAP.get(localCacheKey);if (CollectionUtils.isNotEmpty(tupleTwoList)) {for(TupleTwo<Integer, Object> tupleTwo :tupleTwoList){Integer localHashCode = tupleTwo.getFirst();//相等,才能使用if (localHashCode.equals(scriptContent.hashCode())) {return tupleTwo.getSecond();}}//如果未匹配到,传入的脚本数量不大于缓存的数量,则代表缓存数据存在问题,直接清理掉重新缓存if(maxscriptCont <=tupleTwoList.size()){tupleTwoList.clear();tupleTwoList =null;}}//注意:CopyOnWriteArrayListtupleTwoList = tupleTwoList == null?new CopyOnWriteArrayList<>():tupleTwoList;Class clazz = groovyShell.getClassLoader().parseClass(scriptContent);Object executor = clazz.newInstance();SpringContextUtils.autowireBean(executor);tupleTwoList.add(TupleTwo.of(scriptContent.hashCode(), executor));SCRIPT_MAP.put(localCacheKey,tupleTwoList);return executor;}public static void cleanLocalExecutor(String relationApiKey) {cleanLocalCache(relationApiKey+"_"+VopParamTypeEnum.PARAM_IN.getKey());cleanLocalCache(relationApiKey+"_"+VopParamTypeEnum.PARAM_OUT.getKey());}private static void cleanLocalCache(String localCacheKey) {List<TupleTwo<Integer, Object>> tupleTwoList = SCRIPT_MAP.get(localCacheKey);if(tupleTwoList != null){tupleTwoList.clear();tupleTwoList = null;}SCRIPT_MAP.remove(localCacheKey);}
}

是什么

Groovy 是一种基于 JVM 的动态语言,与 Java 语言紧密集成,可以很方便地在 Java 项目中使用。Groovy 有着简洁的语法、灵活的类型系统、强大的元编程能力,适合编写各种类型的脚本和应用程序。使用groovy也可以实现java程序的动态扩展,和用于插件化的开发,增强系统的可扩展性。

原理

其执行过程是:首先实例化一个GroovyClassLoader的对象,然后通过GroovyClassLoader 解析groovy脚本并生成一个Class文件,在然后实例化一个GroovyObject,通过GroovyObject执行脚本中的方法。

classloader的双亲委派,我们先来分析一下这个GroovyClassloader,看看它的祖先分别是啥:

groovy.lang.GroovyClassLoader@InnerLoader@42607a4f
groovy.lang.GroovyClassLoader@42e99e4a
sun.misc.Launcher.AppClassLoader@58644d46
sun.misc.Launcher.ExtClassLoader@62150f9e

Bootstrap ClassLoadersun.misc.Launcher.ExtClassLoader      // 即Extension ClassLoader  sun.misc.Launcher.AppClassLoader      // 即System ClassLoader  org.codehaus.groovy.tools.RootLoader  // 以下为User Custom ClassLoader  groovy.lang.GroovyClassLoadergroovy.lang.GroovyClassLoader.InnerLoader  

可以看到这种方式比较强大的,其通过类加载的方式进行脚本的加载和解析,使其在java中可以像调用java类的方法一样调用groovy脚本中的方法。因此GroovyClassLoader 适用于需要动态加载和执行 Groovy 脚本的场景,如插件化系统、动态扩展;也适用于一些需要在运行时动态生成和编译代码的场景。

比如我们可以定义个groovy类,其实现一个java接口,在java运行时我们可以将这个groovy加载到spring容器中,通过bean的方式使用groovy脚本。

在 Groovy 中,所有的 Groovy 类都是 Java 类的子类,包括通过 Groovy 脚本动态生成的类。因此,当使用 GroovyClassLoader 加载 Groovy 脚本并编译生成 Groovy 类后,得到的 Class 对象实际上也是 Groovy 类型的 Class 对象,可以被强制转换为 GroovyObject 类型。
GroovyObject 接口是所有 Groovy 类的基类,它定义了 Groovy 类的基本行为和属性。因此,只要一个类实现了 GroovyObject 接口,它就可以被认为是一个 Groovy 类。在 Groovy 中,所有的 Groovy 类都默认实现了 GroovyObject 接口,因此,当我们从 GroovyClassLoader 加载 Groovy 类后,可以直接将其强制转换为 GroovyObject 类型。

调用groovy脚本实现方式

1.使用GroovyClassLoaderprivate static void invoke(String scriptText, String function, Object... objects) throws Exception {GroovyClassLoader classLoader = new GroovyClassLoader();Class groovyClass = classLoader.parseClass(scriptText);try {GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();groovyObject.invokeMethod(function,objects);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}

2.使用ScriptEngine

private static final GroovyScriptEngineFactory scriptEngineFactory = new GroovyScriptEngineFactory();private static <T> T invoke(String script, String function, Object... objects) throws Exception {ScriptEngine scriptEngine = scriptEngineFactory.getScriptEngine();scriptEngine.eval(script);return (T) ((Invocable) scriptEngine).invokeFunction(function, objects);
}

3.使用GroovyShell

private static GroovyShell groovyShell = new GroovyShell();private static <T> T invoke(String scriptText, String function, Object... objects) throws Exception {Script script= groovyShell.parse(scriptText);return (T) InvokerHelper.invokeMethod(script, function, objects);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

某制造企业基于 KubeSphere 的云原生实践

背景介绍 随着业务升级改造与软件产品专案的增多&#xff0c;常规的物理机和虚拟机方式逐渐暴露出一些问题&#xff1a; 大量服务部署在虚拟机上&#xff0c;资源预估和硬件浪费较大&#xff1b;大量服务部署在虚拟机上&#xff0c;部署时间和难度较大&#xff0c;自动化程度…

Linux chmod

chmod 首先chmod 用于修改文件权限&#xff0c;使用命令 ll 查看文件列表&#xff0c;或者使用stat文件名 可以查看其相应的权限 显示的形式为例如 rwx r- - r-- &#xff0c;即所有者拥有读写执行的权限 &#xff0c;同组人员和其他人都只拥有读的权限 一般修改权限为三部分…

加利福尼亚大学|3D-LLM:将3D世界于大规模语言模型结合

来自加利福尼亚大学的3D-LLM项目团队提到&#xff1a;大型语言模型 (LLM) 和视觉语言模型 (VLM) 已被证明在多项任务上表现出色&#xff0c;例如常识推理。尽管这些模型非常强大&#xff0c;但它们并不以 3D 物理世界为基础&#xff0c;而 3D 物理世界涉及更丰富的概念&#xf…

SQL关于having用法及与where的区别

having后面只能接聚合函数 因为having的存在本来就是为了解决&#xff1a;where后面不能接聚合函数&#xff0c;这个问题。 与where的异同&#xff1a; 相同之处&#xff1a; 1.作用都是筛选 2.都可以使用比较运算符&#xff1a;in&#xff0c;between and&#xff0c;lik…

Mybatis 新增/批量新增, 拿到返回的自增主键ID

单个新增 &#xff1a; /** * 插入菜单 * param menuInfo * return */ int insertMenuInfo(MenuInfo menuInfo); xml&#xff1a; <insert id"insertMenuInfo" parameterType"com.XXXX..MenuInfo" keyProperty"id&quo…

GoogleLeNet V2 V3 —— Batch Normalization

文章目录 Batch Normalizationinternal covariate shift激活层的作用BN执行的位置数据白化网络中的BN层训练过程 BN的实验效果MNIST与GoogleLeNet V1比较 GoogleLeNet出来之后&#xff0c;Google在这个基础上又演进了几个版本&#xff0c;一般来说是说有4个版本&#xff0c;之前…

《蛤蟆先生去看心理医生》--- 有感

概述 蛤蟆先生是一个原生家境十分优裕的人&#xff0c;在一定程度上他也将上一代的财富和地位给继承了下来。但其原生家庭中父亲对他要求过于严厉&#xff0c;导致他从小养成了一种讨好型人格&#xff0c;到上一代人去世后性格仍然没有得到成长&#xff0c;以至于最近一段时间他…

Redis 数据库的高可用

文章目录 一.Redis 数据库的持久化1.Redis 高可用概念2.Redis 实现高可用的技术2.1 持久化2.2 主从复制2.3 哨兵2.4 Cluster集群 3.Redis 持久化3.1 持久化的功能3.2 Redis 提供持久化的方式3.2.1 RDB 持久化3.2.2 AOF 持久化&#xff08;append only file&#xff09; 3.3 RDB…

数据结构之栈

&#x1f389;welcome&#x1f389; ✒️博主介绍&#xff1a;博主大一智能制造在读&#xff0c;热爱C/C&#xff0c;会不定期更新系统、语法、算法、硬件的相关博客&#xff0c;浅浅期待下一次更新吧&#xff01; ✈️算法专栏&#xff1a;算法与数据结构 &#x1f618;博客制…

Python建造者模式介绍、使用方法

一、Python建造者模式简介 1. 概念 建造者模式(Builder Pattern)是一种创建型设计模式&#xff0c;它可以将复杂对象的构造与表示分离&#xff0c;使得同样的构建过程可以创建不同的表现形式。该模式通过一步一步创建复杂对象&#xff0c;将对象的构造过程与表示过程解耦。 2.…

web前端tips:js继承——原型链继承

原型链继承 原型链继承是 JavaScript 中实现继承的一种方式&#xff0c;它通过使用原型来实现对象之间的继承关系。 在 JavaScript 中&#xff0c;每个对象都有一个原型&#xff08;prototype&#xff09;&#xff0c;它是一个指向另一个对象的引用。当我们访问一个对象的属性…

什么是算法

算法的概念 算法&#xff08;algorithm&#xff09;是解决一系列问题的清晰指令&#xff0c;也就是&#xff0c;能对一定规范的输入&#xff0c;在有限的时间内获得所要求的输出。 简单来说&#xff0c;算法就是解决一个问题的具体方法和步骤。算法是程序的灵魂 一、算法的特征…

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”

科技云报道原创。 没有人能预见未来&#xff0c;但我们可以因循常识&#xff0c;去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底&#xff0c;由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场&#xff0c;生成式AI成为科技市场热点&#xff0c…

ES6:Object.assign方法详解

ES6&#xff1a;Object.assign方法详解 1、前言2、语法3、基本用法3.1 目标对象和源对象无重名属性3.2 目标对象和源对象有重名属性3.3 有多个源对象3.4 其他情况3.4.1 只有一个参数时&#xff0c;Object.assign会直接返回该参数3.4.2 如果该参数不是对象&#xff0c;则会先转成…

每日一道面试题之介绍一下Iterator

Iterator是Java中的一个接口&#xff0c;用于遍历集合&#xff08;Collection&#xff09;中的元素。通过Iterator&#xff0c;可以按顺序访问集合中的每个元素&#xff0c;而无需了解集合的内部实现细节。 使用Iterator的一般步骤如下&#xff1a; 通过调用集合的iterator()…

SOC FPGA之HPS模型设计(二)

根据SOC FPGA之HPS模型设计(一)&#xff0c; Quartus工程经过全编译后会产生Handoff文件夹、SOPCINFO文件、SVD文件 二、生成Preloader镜像文件 通过信息交换文件Handoff文件生成Preloader&#xff0c;需要用到SOC EDS Preloader也被称为spl(Second Program Loader)或u-boot…

【云原生 • Kubernetes】认识 k8s、k8s 架构、核心概念点介绍

目录 一、Kubernetes 简介 二、Kubernetes 架构 三、Kunbernetes 有哪些核心概念&#xff1f; 1. 集群 Cluster 2. 容器 Container 3. POD 4. 副本集 ReplicaSet 5. 服务 service 6. 发布 Deployment 7. ConfigMap/Secret 8. DaemonSet 9. 核心概念总结 一、Kubern…

基于Ko-time的Springboot单体化调用链追踪实践

目录 前言 一、关于Ko-Time 1、是什么&#xff1f; 2、ko-time更新时间线 二、Ko-time怎么用&#xff1f; 1、依赖引入 2、配置集成 3、权限放行 三、链路追踪 1、系统运行 2、链路追踪 3、长时间调用模拟 总结 前言 熟悉微服务的老司机一定了解&#xff0c;在微服务模…

Web端即时通讯技术(SEE,webSocket)

目录 背景简介个人见解被动推送轮询简介实现 长轮询&#xff08;comet&#xff09;简介实现 比较 主动推送长连接&#xff08;SSE&#xff09;简介实现GETPOST 效果 webSocket简介WebSocket的工作原理:WebSocket的主要优点:WebSocket的主要缺点: 实现用法一用法二 **效果** 比较…

学习笔记|大模型优质Prompt开发与应用课(二)|第四节:大模型帮你写代码,小白也能做程序

文章目录 01软件开发产业趋势与技术革新软件开发产业趋势与技术革新技术性人才很受欢迎软件开发产业趋势与技术革新技术门槛越来越低 02 大模型驱动的软件开发需求分析prompt 产品设计开发和测试prompt输出回复promptpromptprompt回复 发布和部署promptprompt 维护和更新prompt…