Используйте Groovy скрипт из другого Groovy скрипта - PullRequest
1 голос
/ 04 июня 2019

Я хочу использовать нестандартный скрипт 'Util' внутри другого скриптового скрипта. Я не хочу каждый раз загружать класс 'Util' в мой основной скрипт. Поэтому использование оценки или GroovyShell не подходит для моего случая.

Мое java-приложение извлекает из базы данных «основной» основной скрипт, каждый раз анализирует его и вызывает метод test () из основного сценария.

Java-код:

GroovyShell groovyShell = new GroovyShell();
Script parsedScript = groovyShell.parse(scriptBody);

ResultPojo result = (ResultPojo) parsedScript.invokeMethod("test", null);

основной сценарий

public int test(){
    // this will not work at the moment
    int result = GroovyUtils.sum(); 
    return result;
}

Класс 'Util' будет также находиться в базе данных. Классы 'Util' будут каким-то образом загружены при запуске приложения и будут перезагружаться каждые X минут.

class GroovyUtils{

    static int sum() {
        return 2+1;
    }
}

Как я уже сказал, я не хочу «разбирать» класс GroovyUtils внутри «основного» скрипта, потому что это дорого.

В идеале я хочу импортировать скрипт GroovyUtils, когда он мне нужен.

import groovy.GroovyUtils;

public int test(){
    int result = GroovyUtils.sum(); 
    return result;
}

Но для того, чтобы импортировать скрипт, его нужно сохранить в той же папке, в которой работает java-приложение. Java-приложение развертывается на удаленном сервере приложений в формате .war.

Могу ли я каким-то образом динамически загружать GroovyUtils в CLASSPATH, не сохраняя его, чтобы я мог импортировать его из своего основного сценария?

Есть предложения? Мои главные проблемы - это скорость и перезарядка.

1 Ответ

1 голос
/ 04 июня 2019

если вы хотите создать процесс доставки через базу данных, вы можете сделать это, расширив GroovyClassLoader и реализовав открытый класс loadClass (name, lookupScriptFiles, предпочитаетClassOverScript, resol)) метод, который будет искать классы в некоторыхтаблица в базе данных.

Позвольте мне упростить вашу цель и исключить базу данных.

Существует стандартное поведение загрузчики классов : поиск и загрузка классов среди пути к классам

GroovyClassLoader позволяет добавлять новые пути к пути к классам во время выполнения, поэтому он будет искать дополнительные классы в указанной папке или файле jar.

classloader сохраняет проанализированные классы в памяти и загрузчике groovy classloaderпредоставляет защищенный метод для удаления определения класса по имени: removeClassCacheEntry (java.lang.String)

и, наконец, пример:

/ myprj / classes / util /MyClass.groovy

package util
class MyClass{
    def echo(msg){ println msg }
}

код для запуска основного скрипта

//create shell and init classloader just once
GroovyShell gs = new GroovyShell()
gs.getClassLoader().addClasspath("/myprj/classes/")

//forces classloader to recompile on file change
//this is alternative to removeClassCacheEntry
//but in some specific cases this reload will not work
gs.getClassLoader().setShouldRecompile​(true)

Script script = gs.parse('''
  import util.MyClass
  new MyClass().echo("hello world")
''')

script.run() // prints 'hello world'

//removeClassCacheEntry is alternative to setShouldRecompile​
//you can use it to remove compiled class from this classloader
println gs.getClassLoader().getLoadedClasses() // outputs util.MyClass, and Script1
gs.getClassLoader().removeClassCacheEntry("util.MyClass")
println gs.getClassLoader().getLoadedClasses() // outputs Script1

возврат к тБаза данных: у вас может быть поток демона, который сканирует базу данных на предмет нестандартных изменений кода и экспортирует измененные источники в папку, которая была определена как дополнительный путь к классу и запускает removeClassCacheEntry для загрузчика классов.Таким образом, следующий доступ к удаленному классу заставит его проанализировать GroovyClassLoader.

ПРИМЕЧАНИЕ: при использовании динамической загрузки классов вы можете столкнуться с ситуацией, когда две версии одного и того же класса присутствуют в памяти, и они не будут сопоставимыи присваивается друг другу.Таким образом, вы можете получить ошибку вроде: could not assign MyClass to MyClass

...