Покажите свои навыки Groovy! Практика динамического программирования в SpringBoot
Покажите свои навыки Groovy! Практика динамического программирования в SpringBoot

Groovy — единственный язык сценариев, расширяющий возможности платформы Java. Он предоставляет Java-подобный синтаксис со встроенными картами, списками, методами, классами, замыканиями и генераторами. Языки сценариев не заменяют языки системного программирования, они дополняют друг друга.

За Groovy стоит знаменитый Gradle. В будущем Spring будет все чаще использовать Groovy, и даже при отслеживании проектов с помощью Jira за этим стоит Groovy.

на самом деле,Сразу Сценарии применения С точки зрения,Java Произошло все больше событий Groovy Появился на заднем плане. Для общей разработки приложений, если их можно использовать. Java Его можно использовать Круто, единственная трудность заключается в том, сможет ли он набрать достаточное количество людей.

Сценарии применения

  • Подключите существующие компоненты
  • Обработка нескольких типов объектов, которые часто меняются.
  • Имеет графический интерфейс пользователя
  • Иметь быстро меняющиеся возможности

" Примечание. Сегодня мы рассказываем об использовании сценариев Groovy для реализации динамического программирования в проектах SpringBoot, что делает бизнес-логику динамичной и значительно повышает эффективность и гибкость разработки.

Интеграция и использование

Затем давайте представим, как SpringBoot интегрирует сценарии Groovy и применяет их в реальной разработке.

Первый шаг — интеграция со SpringBoot.

1. Файл pom.xml выглядит следующим образом:

Язык кода:javascript
копировать
<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>

Шаг 2. Напишите Groovy-версию «Hello World».

1. Код сценария HelloWorld.groovy

Язык кода:javascript
копировать
package groovy

def HelloWorld(){
    println "hello world"
}

2. Создайте тестовый класс GroovyTest.java.

Язык кода:javascript
копировать
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. Результаты операции

картина

Шаг 3. Передайте переменные и получите возвращаемое значение.

1. Переменные и возвращаемые значения Код скрипта Groovy

Язык кода:javascript
копировать
package groovy

/**
 * Простое дополнение
 * @param a Номер а
 * @param b Номер б
 * @return и
 */
def add(int a, int b) {
    return a + b
}

/**
 * карта преобразована в строку
 * @param paramMap Карта параметров
 * @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.

Язык кода:javascript
копировать
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 Номер а\n" +
                " * @param b Номер б\n" +
                " * @return и\n" +
                " */\n" +
                "def add(int a, int b) {\n" +
                "    return a + b\n" +
                "}\n" +
                "\n" +
                "/**\n" +
                " * карта преобразована в строку\n" +
                " * @param paramMap Карта параметров\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. Результаты операции

картина

Шаг 4. Запустите SpringBoot

Получите bean-компоненты в контейнере SpringBoot через SpringContextUtil в сценарии Groovy.

1. Создайте SpringContextUtil.java.

Язык кода:javascript
копировать
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;
    }

    /**
     * Получить по имени Bean.
     *
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * Проведите Бин через класс.
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * Вернуть указанный Bean через имя и Clazz
     *
     * @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.

Язык кода:javascript
копировать
package com.example.springbootgroovy.service;

import org.springframework.stereotype.Service;

@Service
public class GroovyTestService {

    public void test(){
        System.out.println("Я являюсь членом класса SpringBoot, но этот метод вызывается GroovyСкрипт");
    }

}

3. Сценарий Groovy выглядит следующим образом.

Язык кода:javascript
копировать
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. Код класса запуска следующий:

Язык кода:javascript
копировать
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 станут самым мощным оружием против вашей системы! ! !

Кроме того, если сценарий Groovy используется неправильно, это приведет к OOM и, в конечном итоге, к сбою сервера.

" Мое первоначальное использование

Язык кода:javascript
копировать
public static List<JSONObject> invokeMethod(String templateScript, JSONObject configParam) {
     Binding groovyBinding = new Binding();
     GroovyShell groovyShell = new GroovyShell(groovyBinding);
     Script script = groovyShell.parse(templateScript);
     Object[] params = new Object[]{configParam};
     List<JSONObject> resultList = (List<JSONObject>) script.invokeMethod("methodName", params);
     return resultList;
 }

Такое использование определенно неправильно. Оно эквивалентно созданию экземпляров GroovyShell, Script и т. д. при каждом вызове этого метода. По мере увеличения количества вызовов неизбежно возникает OOM.

" Для первой модификации добавьте строку в конец метода: groovyShell.getClassLoader().clearCache();

То есть вызов методаclearCache в конце метода может очистить GroovyShell, Script и другие экземпляры, но этого все равно недостаточно. Причиной OOM является не просто слишком большое количество экземпляров GroovyShell, Script и т. д. Изучив информацию, мы обнаружили, что если код Java в скрипте также создает объекты или новые экземпляры, даже если GroovyShell уничтожен, объекты в скрипте не будет уничтожен.

Например, следующий скрипт создаст объект ArrayList. Этот объект не исчезнет при исчезновении экземпляров GroovyShell, Script и т. д., поэтому проблемы все равно будут.

Язык кода:javascript
копировать
def test(){
    List<String> list = new ArrayList<>();
}

" Во втором преобразовании был добавлен SCRIPT_MAP, а существующие экземпляры Groovy были помещены в кэш для обслуживания.

Язык кода:javascript
копировать
/**
 * Кэшируйте сценарии, чтобы избежать создания слишком большого количества
 */
private static final Map<String, Script> SCRIPT_MAP = Maps.newHashMap();

private static final GroovyClassLoader CLASS_LOADER = new GroovyClassLoader();

public static Script loadScript(String key, String rule) {
    if (SCRIPT_MAP.containsKey(key)) {
        return SCRIPT_MAP.get(key);
    }
    Script script = loadScript(rule, new Binding());
    SCRIPT_MAP.put(key, script);
    return script;
}


public static Script loadScript(String rule, Binding binding) {
    if (StringUtils.isEmpty(rule)) {
        return null;
    }
    try {
        Class ruleClazz = CLASS_LOADER.parseClass(rule);
        if (ruleClazz != null) {
            log.info("load rule:" + rule + " success!");
            return InvokerHelper.createScript(ruleClazz, binding);
        }
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    } finally {
        CLASS_LOADER.clearCache();
    }
    return null;
}

Преимущество этого метода в том, что он решает проблему ООМ.,Но есть и проблема,Если содержимое Скрипта изменено,Необходимо очиститьSCRIPT_MAP,Перезагрузите экземпляр скрипта.

<END>

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose