SpringBoot整合Groovy脚本实现动态编程详解

作者:summo 时间:2023-04-02 03:24:16 

Groovy简介

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

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

应用场景

  • 连接已有的组件

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

  • 具有图形化用户界面

  • 拥有快速变化的功能

Groovy脚本的基础概念请移步

Groovy 简介

集成与使用

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

第一步、与SpringBoot集成

1、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版本的&ldquo;Hello World&rdquo;

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、运行结果

SpringBoot整合Groovy脚本实现动态编程详解

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

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脚本实现动态编程详解

第四步、启动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

运行结果如下

SpringBoot整合Groovy脚本实现动态编程详解

注意!!!

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

来源:https://juejin.cn/post/7139877924676567048

标签:SpringBoot,Groovy,动态编程
0
投稿

猜你喜欢

  • 解决Android studio 2.3升级到Android studio 3.0 后apt报错问题

    2023-05-17 13:56:50
  • ToStringBuilder类的一些心得

    2022-10-10 04:02:27
  • C#实现打印与打印预览功能的思路及代码

    2021-09-17 02:51:06
  • Java状态设计模式实现对象状态转换的优雅方式

    2023-11-20 10:33:59
  • 在AndroidManifest.xml中uses-sdk内属性意思

    2021-10-08 17:16:09
  • Maven 生成打包可执行jar包的方法步骤

    2023-01-02 14:53:15
  • Kotlin协程Channel特点及使用细节详解

    2021-06-03 08:12:34
  • Mybatis-Plus自动填充更新操作相关字段的实现

    2023-06-04 22:37:12
  • C语言实现代码雨效果

    2021-11-26 18:11:20
  • 基于自定义Toast全面解析

    2023-08-27 19:18:55
  • Android开源库自定义相机模块

    2023-08-31 04:21:59
  • 基于Unity3D实现仿真时钟详解

    2021-05-24 15:11:34
  • Java避免死锁_动力节点Java学院整理

    2023-05-07 15:02:03
  • C# 调用 JavaWebservice服务遇到的问题汇总

    2023-04-23 04:00:49
  • Handler与Android多线程详解

    2022-04-26 18:23:10
  • obix协议在java中的配置和使用详解

    2023-11-25 20:59:42
  • C#开发WPF程序中的弱事件模式

    2022-11-21 12:50:34
  • 如何用C#实现SAGA分布式事务

    2022-11-29 20:34:49
  • MyBatis Oracle 自增序列的实现方法

    2023-08-03 11:30:08
  • Java中JMM与volatile关键字的学习

    2022-03-24 00:12:00
  • asp之家 软件编程 m.aspxhome.com