Groovy的metaClass作用域是什么?

3

我是一个可以运行脚本以自动化特定任务的应用程序。我想在这些脚本中使用元编程来优化代码大小和可读性。因此,不是这样写:

try {
    def res = factory.allocate();
    ... do something with res ...
} finally {
    res.close()
}

I'd like to

Factory.metaClass.withResource = { c -> 
    try {
        def res = factory.allocate();
        c(res)
    } finally {
        res.close()
    }
}

因此,脚本编写人员可以编写:

factory.withResource { res ->
    ... do something with res ...
}

(我还可以做适当的错误处理等)。
现在我想知道什么时候以及如何实现这个功能。我可以将元类的操作附加到每个脚本前面的标头中,但我担心如果两个用户同时运行脚本(并发访问元类),会发生什么。
元类的范围是什么?编译器?脚本环境?Java VM?加载Groovy的类加载器?
我的想法是,如果Groovy元类具有VM范围,则可以在启动期间运行一次设置脚本。

try: ... finally:?这是Python吗? - Will
@WillP:发现的好 :-) 已修复。 - Aaron Digulla
2个回答

3

元类存在于每个类加载器中[需要引用]:

文件/tmp/Qwop.groovy:

class Qwop { }

File /tmp/Loader.groovy:

Qwop.metaClass.bar = { }
qwop1 = new Qwop()
assert qwop1.respondsTo('bar')

loader = new GroovyClassLoader()
clazz = loader.parseClass new File("/tmp/Qwop.groovy")

clazz.metaClass.brap = { 'oh my' }

qwop = clazz.newInstance()

assert !qwop.respondsTo('bar')
assert qwop1.respondsTo('bar')

assert qwop.brap() == "oh my"
assert !qwop1.respondsTo('brap')

// here be custom classloaders
new GroovyShell(loader).evaluate new File('/tmp/QwopTest.groovy')

以下是用于测试作用域元类的脚本(/tmp/QwopTest.groovy):

assert !new Qwop().respondsTo('bar')
assert new Qwop().respondsTo('brap')

执行:

$ groovy Loaders.groovy 
$ 

如果你有一组良好定义的类,你可以在这些类的基础上应用元编程,就像所添加的brap方法一样,在你的类加载器中加载它们。

2

对于这种情况的另一个选择,更适合许多场景的是使用扩展模块。

package demo

class FactoryExtension {
    static withResource(Factory instance, Closure c) {
        def res
        try {
            res = instance.allocate()
            c(res)
        } finally {
            res?.close()
        }
    }
}

编译它并将其放入一个jar文件中,该文件包含一个位于META-INF/services/org.codehaus.groovy.runtime.ExtensionModule的文件,其中包含类似于以下内容的内容...

moduleName=factory-extension-module
moduleVersion=1.0
extensionClasses=demo.FactoryExtension

那么,为了让其他人使用您的扩展程序,他们只需要将该jar文件放在他们的CLASSPATH上即可。有了这些准备工作,用户可以执行以下操作...

factoryInstance.withResource { res ->
    ... do something with res ...
}

更多关于扩展模块的信息,请访问http://docs.groovy-lang.org/docs/groovy-2.3.6/html/documentation/#_extension_modules

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接