Spring Boot 整合 Groovy 脚本,实现动态编程

news2024/7/6 3:53:26

Groovy简介

Groovy 是增强 Java 平台的唯一的脚本语言。它提供了类似于 Java 的语法,内置映射(Map)、列表(List)、方法、类、闭包(closure)以及生成器。脚本语言不会替代系统编程语言,两者是相互补充的。

大名鼎鼎的 Gradle,背后是 Groovy。Spring 的未来越来越多的使用 Groovy,甚至在用 Jira 跟踪项目时,背后也有 Groovy。实际上,就应用场景而言,Java 开发已经有越来越多的 Groovy 出现在后台了。而对于一般的应用开发,只要能用 Java 就都能用到 Groovy,唯一的难点只在于能不能招到足够的人员。

应用场景

  • 连接已有的组件

  • 处理经常变化的多种类型的实体

  • 具有图形化用户界面

  • 拥有快速变化的功能

Groovy脚本的基础概念请移步

  • http://mvnbook.com/groovy-introduction.html

集成与使用

那么接下来介绍SpringBoot如何集成Groovy脚本,并应用到实际开发中。

第一步、与SpringBoot集成

pom.xml文件如下:

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.7</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

第二步、写出Groovy版本的“Hello World”

1、HelloWorld.groovy脚本代码

package groovy

def HelloWorld(){
    println "hello world"
}

2、创建测试类GroovyTest.java

package com.example.springbootgroovy.service;

import groovy.lang.GroovyShell;
import groovy.lang.Script;

/**
 * 这个是Groovy的第一个小程序,脚本为:
 * 
 package groovy
 
 def helloworld(){
  println "hello world"
 }
 *
 */
public class GroovyTest {

    public static void main(String[] args) throws Exception {
        //创建GroovyShell
        GroovyShell groovyShell = new GroovyShell();
        //装载解析脚本代码
        Script script = groovyShell.parse("package groovy\n" +
                "\n" +
                "def HelloWorld(){\n" +
                "    println \"hello world\"\n" +
                "}");
        //执行
        script.invokeMethod("HelloWorld", null);
    }
}

3、运行结果

第三步、传入变量与获取返回值

1、变量与返回值Groovy脚本代码

package groovy

/**
 * 简易加法
 * @param a 数字a
 * @param b 数字b
 * @return 和
 */
def add(int a, int b) {
    return a + b
}

/**
 * map转化为String
 * @param paramMap 参数map
 * @return 字符串
 */
def mapToString(Map<String, String> paramMap) {
    StringBuilder stringBuilder = new StringBuilder();
    paramMap.forEach({ key, value ->
        stringBuilder.append("key:" + key + ";value:" + value)
    })
    return stringBuilder.toString()
}

2、创建测试类GroovyTest2.java

package com.example.springbootgroovy.service;

import groovy.lang.GroovyShell;
import groovy.lang.Script;

import java.util.HashMap;
import java.util.Map;

/**
 * 向Groovy脚本中传入变量,以及获取返回值
 */
public class GroovyTest2 {
    public static void main(String[] args) {
        //创建GroovyShell
        GroovyShell groovyShell = new GroovyShell();
        //装载解析脚本代码
        Script script = groovyShell.parse("package groovy\n" +
                "\n" +
                "/**\n" +
                " * 简易加法\n" +
                " * @param a 数字a\n" +
                " * @param b 数字b\n" +
                " * @return 和\n" +
                " */\n" +
                "def add(int a, int b) {\n" +
                "    return a + b\n" +
                "}\n" +
                "\n" +
                "/**\n" +
                " * map转化为String\n" +
                " * @param paramMap 参数map\n" +
                " * @return 字符串\n" +
                " */\n" +
                "def mapToString(Map<String, String> paramMap) {\n" +
                "    StringBuilder stringBuilder = new StringBuilder();\n" +
                "    paramMap.forEach({ key, value ->\n" +
                "        stringBuilder.append(\"key:\" + key + \";value:\" + value)\n" +
                "    })\n" +
                "    return stringBuilder.toString()\n" +
                "}");
        //执行加法脚本
        Object[] params1 = new Object[]{1, 2};
        int sum = (int) script.invokeMethod("add", params1);
        System.out.println("a加b的和为:" + sum);
        //执行解析脚本
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("科目1", "语文");
        paramMap.put("科目2", "数学");
        Object[] params2 = new Object[]{paramMap};
        String result = (String) script.invokeMethod("mapToString", params2);
        System.out.println("mapToString:" + result);
    }
}

3、运行结果

图片

第四步、启动SpringBoot,在Groovy脚本中通过SpringContextUtil获取SpringBoot容器中的Bean

1、创建SpringContextUtil.java

package com.example.springbootgroovy.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Spring上下文获取
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtil.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通过name获取 Bean.
     *
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     *
     * @param name
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

2、创建GroovyTestService.java,并加上@Service注解加入到SpringBoot容器中

package com.example.springbootgroovy.service;

import org.springframework.stereotype.Service;

@Service
public class GroovyTestService {

    public void test(){
        System.out.println("我是SpringBoot框架的成员类,但该方法由Groovy脚本调用");
    }

}

3、Groovy脚本如下

package groovy

import com.example.springbootgroovy.service.GroovyTestService
import com.example.springbootgroovy.util.SpringContextUtil

/**
 * 静态变量
 */
class Globals {
    static String PARAM1 = "静态变量"
    static int[] arrayList = [1, 2]
}

def getBean() {
    GroovyTestService groovyTestService = SpringContextUtil.getBean(GroovyTestService.class);
    groovyTestService.test()
}

4、启动类代码如下

package com.example.springbootgroovy;

import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/groovy")
@SpringBootApplication
public class SpringBootGroovyApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootGroovyApplication.class, args);
    }

    @RequestMapping("/test")
    public String test() {
        //创建GroovyShell
        GroovyShell groovyShell = new GroovyShell();
        //装载解析脚本代码
        Script script = groovyShell.parse("package groovy\n" +
                "\n" +
                "import com.example.springbootgroovy.service.GroovyTestService\n" +
                "import com.example.springbootgroovy.util.SpringContextUtil\n" +
                "\n" +
                "/**\n" +
                " * 静态变量\n" +
                " */\n" +
                "class Globals {\n" +
                "    static String PARAM1 = \"静态变量\"\n" +
                "    static int[] arrayList = [1, 2]\n" +
                "}\n" +
                "\n" +
                "def getBean() {\n" +
                "    GroovyTestService groovyTestService = SpringContextUtil.getBean(GroovyTestService.class);\n" +
                "    groovyTestService.test()\n" +
                "}");
        //执行
        script.invokeMethod("getBean", null);
        return "ok";
    }
}

5、启动后调用接口:http://localhost:8080/groovy/test,运行结果如下

图片

注意!!!

通过第四步中我们可以看到,在Groovy中是可以获取到SpringBoot容器对象的。虽然很方便,但是很危险。如果没有做好权限控制,Groovy脚本将会成为攻击你系统最有力的武器!!

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

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

相关文章

「Redis数据结构」哈希对象(Hash)

「Redis数据结构」哈希对象&#xff08;Hash&#xff09; 文章目录「Redis数据结构」哈希对象&#xff08;Hash&#xff09;一、概述二、编码ZipListHashTable三、编码转换一、概述 Redis中hash对象是一个string类型的field和value的映射表&#xff0c;hash特别适合用于存储对…

RabbitMQ:消息模型

RabbitMQ 提供了 6 种消息模型&#xff0c;分别为&#xff1a;单生产单消费模型&#xff08;Hello World&#xff09;、消息分发模型&#xff08;Work queues&#xff09;、Fanout 消息订阅模式&#xff08;Publish/Subscribe&#xff09;、Direct 路由模式&#xff08;Routing…

基于JSP的手工艺品在线网站

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括手工艺品在线网站的网络应用&#xff0c;在外国手工艺品已经是很普遍的方式&#xff0c;不过国内的手工艺品可能还处于起步阶段。手工艺品在线网站具有在线下单功能。手…

详解vue中watch的用法

前言 说到 vue 中的 watch 方法&#xff0c;大家可能首先想到&#xff0c;它是用来监听数据的变化&#xff0c;一旦数据发生变化可以执行一些其他的操作。但是 watch 的操作可不止如此&#xff0c;本章就带大家一起深剖细析 vue 中的 watch 方法。 watch&#xff1f; 因为 vue…

DocuWare平台——用于文档管理和工作流程自动化的内容服务平台详细介绍(上)

DocuWare平台——用于文档管理和工作流程自动化的内容服务平台 成功实现办公自动化所需的一切 DocuWare 是一个先进的平台&#xff0c;可让您集中、快速、有效地管理、处理和利用业务信息。 我们的文档管理和工作流程解决方案的各项功能可以集成到任何 IT 系统中&#xff0c;…

源码解析:从 kubelet、容器运行时看 CNI 的使用

这是 Kubernetes 网络学习的第三篇笔记。 深入探索 Kubernetes 网络模型和网络通信认识一下容器网络接口 CNI&#xff08;本篇&#xff09;源码分析&#xff1a;从 kubelet、容器运行时看 CNI 的使用从 Flannel 学习 Kubernetes VXLAN 网络Cilium CNI 与 eBPF... 在上一篇中&…

web前端期末大作业 基于HTML+CSS+JavaScript程序员个人博客模板(web学生作业源码)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

翻译: ChatGPT 的激发敬畏、恐惧、特技和试图绕过其护栏的尝试

来自 OpenAI 的新聊天机器人正在激发敬畏、恐惧、特技和试图绕过其护栏的尝试。 以下是 DALL-E 2 在给出提示时生成的内容&#xff0c;“采用 AI 聊天机器人形式的分布式语言超级大脑。” “A distributed linguistic superbrain that takes the form of an A.I. chatbot.” 信…

WPS文件转Excel文件怎么转?建议看看这些方法

小伙伴们平时在接收文件的时候&#xff0c;有没有发现有些文件是以WPS格式进行保存的。这种格式的文件&#xff0c;如果没有使用相关的软件是没办法直接打开的。这种时候&#xff0c;其实我们可以将WPS转成其它office格式就可以打开它&#xff0c;进行编辑了。那你们知道WPS转E…

面试官:你说说Springboot的启动过程吧(5万字分析启动过程)

文章目录前言一、Springboot是什么二、启动流程2.1 构建Spring Boot项目2.2 启动的日志2.3 启动流程分析说明2.3.1 第一部分&#xff1a;SpringApplication的构造函数A、webApplicationType&#xff08;web应用类型&#xff09;B、引导注册初始化器C、设置初始化器D、设置监听器…

嵌入式开发-STM32硬件SPI驱动TFT屏

嵌入式开发-STM32硬件SPI驱动TFT屏这次用到的TFT屏CubeMX设置代码编写增加的内容需要注意问题代码下载这次用到的TFT屏 现在的TFT屏幕已经很便宜了&#xff0c;65536色屏幕&#xff0c;2.8英寸&#xff0c;分辨率320X240的液晶屏才20元&#xff0c;我为了图省事&#xff0c;多配…

[附源码]Nodejs计算机毕业设计基于JAVA快递配送平台Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

SpringBoot整合GitLab-CI实现持续集成

写在前面 &#x1f341;个人主页&#xff1a;微枫Micromaple ✨本期专栏&#xff1a;《0到1项目搭建》欢迎订阅学习~ &#x1f4cc;源码获取&#xff1a;GitCode、GitHub、码云Gitee 持续更新中&#xff0c;别忘了 star 喔~ 在企业开发过程中&#xff0c;我们开发的功能或者是修…

python之筛选图像中是否存在黑白背景

python之筛选图像中是否存在黑白背景 紧接上篇文章的需求&#xff0c;需要进行功能增加 某些图片存在背景丢失问题&#xff0c;出现黑白背景现象&#xff0c;这种需要排查&#xff0c;同样交给了自动化处理。 这次不比上次了&#xff0c;我搜罗了一堆资料&#xff0c;全是什么…

【实时数仓】DWD层需求分析及实现思路、idea环境搭建、实现DWD层处理用户行为日志的功能

文章目录一 DWD层需求分析及实现思路1 分层需求分析2 每层的职能3 DWD层职能详细介绍&#xff08;1&#xff09;用户行为日志数据&#xff08;2&#xff09;业务数据4 DWD层数据准备实现思路二 环境搭建1 创建maven工程2 修改配置文件&#xff08;1&#xff09;添加依赖&#x…

Faster RCNN精读

Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks Faster R-CNN&#xff1a;使用区域建议网络实现实时目标检测 优异的网络模型总是经得起时间的推敲&#xff0c;Faster RCNN便是其中一员。 目录 一、摘要 二、结论 三、介绍和相关工作 …

R语言析因设计分析:线性模型中的对比

对比度可用于对线性模型中的处理进行比较。 常见的用途是使用析因设计时&#xff0c;除析因设计外还使用控制或检查处理。在下面的第一个示例中&#xff0c;有两个级别&#xff08;1和2&#xff09;的两个处理&#xff08;D和C&#xff09;&#xff0c;然后有一个对照 处理。此…

周末来哥家小聚一下

欢迎关注勤于奋 每天12点准时更新国外LEAD相关技术 是的&#xff0c;周末来哥家小聚&#xff0c;他们这儿人不多&#xff0c;就是一些认识的人&#xff0c;没有外人&#xff0c;加上疫情&#xff0c;一般不聚集&#xff0c;大家都清楚没事。 在他家没事&#xff0c;就陪小朋友…

灵活的类加载器OSGI

灵活的类加载器OSGI 简介 OSGi中的每个模块&#xff08;称为Bundle&#xff09;与普通的Java类库区别并不太大&#xff0c;两者一般都以JAR格式进行 封装[2]&#xff0c;并且内部存储的都是Java的Package和Class。但是一个Bundle可以声明它所依赖的Package&#xff08;通 过I…

最近的一点杂感

这是学习笔记的第 2444篇文章最近居家办公几周了&#xff0c;除了工作也能想想生活的事情&#xff0c;说说最近自己比较深的几四点感受吧。熵增和待办事项最初居家办公的时候&#xff0c;我们也有日会&#xff0c;也会有一些频繁的沟通&#xff0c;但是总是感觉目标的达成效果上…