【问题标题】:How do I undo meta class changes after executing GroovyShell?执行 GroovyShell 后如何撤消元类更改?
【发布时间】:2010-12-09 09:55:10
【问题描述】:

例如,如果我执行一个 Groovy 脚本,它会修改 String 元类,添加一个方法 foo()

GroovyShell shell1 = new GroovyShell();
shell1.evaluate("String.metaClass.foo = {-> delegate.toUpperCase()}");

当我创建一个新的 shell 并执行它时,更改仍然存在

GroovyShell shell2 = new GroovyShell();
Object result = shell2.evaluate("'a'.foo()");

有没有办法在执行 GroovyShell 后撤消所有元类更改?我试过了

shell1.getClassLoader().clearCache();

shell1.resetLoadedClasses();

但这并没有改变。

【问题讨论】:

  • 我可以用一些类加载器来做这个吗?

标签: groovy metaprogramming


【解决方案1】:

你可以使用

GroovySystem.metaClassRegistry.removeMetaClass(String.class);

恢复对 String 元类所做的所有更改。

或者,您只能更改某个 String 实例的元类,因此并非所有 String 实例都会受到影响。

【讨论】:

  • 谢谢。但是,如果我不知道已经进行了哪些元类更改,那该怎么办。想想像 Groovy Web Console 这样的应用程序,不同的用户在其中执行 Groovy 脚本。我希望这些用户不要干涉。
  • 在下面查看我的答案,它解决了您不知道哪些元类已更改的问题。
【解决方案2】:

您也可以使用 MetaClassRegistryCleaner。

在做一些元类改变之前,你可以做

MetaClassRegistryCleaner registryCleaner = MetaClassRegistryCleaner.createAndRegister()
GroovySystem.metaClassRegistry.addMetaClassRegistryChangeEventListener(registryCleaner)

当您想要将元类更改重置为之前的状态时。

你可以的

registryCleaner.clean()  
GroovySystem.metaClassRegistry.removeMetaClassRegistryChangeEventListener(registryCleaner)

这样您可以重置在此期间所做的所有元类更改。

【讨论】:

    【解决方案3】:

    我意识到这是一个较老的问题,但当我搜索完全相同的问题时,这是 Google 上的第一个结果。

    我选择的解决方案是将 groovy 放入一个新的类加载器(通过使用 plexus-classworlds),所以当脚本完成时,类加载器被释放(因此对元类的任何更改也被释放)。

    【讨论】:

    • @JohnMercier 上面的回答没有帮助吗?
    • 这在很多方面都比注册表清理更好,尤其是允许并发执行。
    猜你喜欢
    • 2018-11-28
    • 2013-07-29
    • 2011-04-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2021-05-20
    相关资源
    最近更新 更多