Иногда вам нужны особые меры. Не для того, чтобы 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методы.
Два: овладеть GroovyClassLoaderJava-кодом
Иногда вам нужно получить 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 кодирования!