Groovy'的范围;什么是元类?

Groovy'的范围;什么是元类?,groovy,scope,metaclass,Groovy,Scope,Metaclass,我有一个应用程序,可以运行脚本来自动化某些任务。我想在这些脚本中使用元编程来优化代码大小和可读性。因此,不是: try { def res = factory.allocate(); ... do something with res ... } finally { res.close() } 我想 Factory.metaClass.withResource = { c -> try { def res = factory.alloca

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

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

Factory.metaClass.withResource = { c -> 
    try {
        def res = factory.allocate();
        c(res)
    } finally {
        res.close()
    }
}
因此脚本编写者可以编写:

factory.withResource { res ->
    ... do something with res ...
}
(我可以做正确的错误处理等)

现在我想知道我什么时候和怎样才能实现这一点。我可以将对元类的操作附加到每个脚本的头中,但我担心如果两个用户同时运行脚本(并发访问元类),会发生什么情况

元类的范围是什么?编译器?脚本环境?Java虚拟机?加载Groovy的类加载器


我的理由是,如果Groovy元类具有VM作用域,那么我可以在启动期间运行一次安装脚本。

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

文件
/tmp/Qwop.groovy

class Qwop { }
assert !new Qwop().respondsTo('bar')
assert new Qwop().respondsTo('brap')
文件
/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
):

执行:

$ groovy Loaders.groovy 
$ 

如果您有一组定义良好的类,您可以根据添加的
brap
方法,在类加载器加载的类之上应用元编程。

这种方法的另一个更好的选择是使用扩展模块

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
factoryInstance.withResource { res ->
    ... do something with res ...
}
然后,为了让某人使用您的扩展,他们只需要将jar文件放在他们的类路径上。有了这些,用户可以做这样的事情

moduleName=factory-extension-module
moduleVersion=1.0
extensionClasses=demo.FactoryExtension
factoryInstance.withResource { res ->
    ... do something with res ...
}

有关扩展模块的更多信息,请访问。

try:。。。最后:
?那是蟒蛇吗?@WillP:Good catch:-)修正了。