Иногда вам нужны особые меры. Не для того, чтобы Groovy работал, а для того, чтобы сделать ваши приложения или фреймворки немного более мощными или универсальными.
Вот две техники загрузки классов, которые я использовал в сочетании с Groovy, чтобы сделать жизнь веселее и интереснее.
Один: избавиться от Groovy
Иногда вам нужно заполучить ClassLoader
тот, который не включает классы Groovy. Иногда вам нужно иметь ClassLoader
только те классы, которые поставляются с JVM.
У каждого Java-приложения есть ClassLoader
только классы JVM, и вы можете получить его, если знаете, как.
java.lang.ClassLoader
Класс имеет статический getSystemClassLoader()
метод , который возвращает , ClassLoader
который содержит все классы на CLASSPATH , когда виртуальная машина начала:
ClassLoader.systemClassLoader.loadClass "some.class.on.the.ClassPath"
Это ClassLoader
имеет один или несколько родительских ClassLoader
с. На ClassLoader
вершине этой иерархии находится только классы JVM. Когда вы найдете ClassLoader
без родителей, вы знаете, что нашли его:
def classLoader = ClassLoader.systemClassLoader
while (classLoader.parent) {
classLoader = classLoader.parent
}
Эта маленькая рутина поднимает тебя на вершину ClassLoader
. Теперь вы можете использовать это, чтобы создать новую ClassLoader
иерархию. Требуется только создать новый URLClassLoader
и указать расположение файлов JAR, которые вы хотите включить:
def classLoader = ClassLoader.systemClassLoader
while (classLoader.parent) {
classLoader = classLoader.parent
}
def newClassLoader = new URLClassLoader([new File("location/to.jar").toString().toURL()] as URL[], classLoader)
Теперь у вас есть новый ClassLoader
. Предупреждение: он не включает Groovy, если вы не добавляете JAR Groovy специально, и все классы, которые уже были загружены, будут загружены снова, увеличивая объем памяти вашего приложения. Кроме того, не создавайте слишком много новых ClassLoader
файлов в одном приложении, поскольку они имеют тенденцию вызывать утечки памяти. Создание одного или нескольких должно быть хорошо. Классы, загруженные с новым ClassLoader
, не будут совместимы с классами, загруженными текущей системой ClassLoader
, за исключением классов JVM.
Вы можете улучшить этот код, используя org.apache.tools.ant.launch.Locator
класс (поставляется с Ant). Его fileToURL()
метод немного лучше работает при преобразовании java.io.File
объектов в java.net.URL
методы.
Два: овладеть GroovyClassLoader
Java-кодом
Иногда вам нужно получить groovy.lang.GroovyClassLoader
объект в коде Java. Это может произойти, например, когда код Java вызывается из кода Groovy. GroovyClassLoader
Как правило, они находятся в нижней части ClassLoader
иерархий, и иногда вам нужно загружать классы, GroovyClassLoader
а не где-либо еще в ClassLoader
иерархии.
Однако ваш Java-код, скорее всего, не был загружен GroovyClassLoader
, так как его заполучить? Вы можете передать это явно из вашего Groovy-кода, но это не практично. Вместо этого использовать sun.reflect.Reflection
класс? Никогда не слышал об этом? Тогда пришло время познакомиться с getCallerClass()
методом.
Когда Groovy-код вызывает Java-код, то где-то в стеке есть класс Groovy, который был загружен с помощью GroovyClassLoader
. Вот как можно получить его из кода Java:
import sun.reflect.Reflection;
import groovy.lang.GroovyClassLoader;
public class MyClass {
public void myMethod() throws Exception {
int frame = 1;
// number of levels above you in the stack
Class c = Reflection.getCallerClass(frame);
while (c != null && !(c.getClassLoader() instanceof GroovyClassLoader)) {
frame++;
c = Reflection.getCallerClass(frame);
}
if (c != null) {
GroovyClassLoader gcl = (GroovyClassLoader) c.getClassLoader();
// do Groovy stuff here
Class newClass = gcl.parseClass("class MyNewClass{}");
}
}
}
Эти приемы показывают, насколько Groovy интегрирован с JVM и как Groovy генерирует надлежащий байт-код Java.
Удачного Groovy кодирования!