在执行GroovyShell之后,如何撤消元类更改?

在执行GroovyShell之后,如何撤消元类更改?,groovy,metaprogramming,Groovy,Metaprogramming,例如,如果我执行一个Groovy脚本,该脚本修改字符串元类,添加一个方法foo() 当我在此之后创建一个新的shell并执行它时,更改仍然存在 GroovyShell shell2 = new GroovyShell(); Object result = shell2.evaluate("'a'.foo()"); 在执行GroovyShell之后,有没有办法撤消所有元类更改?我试过了 shell1.getClassLoader().clearCache(); 及 但这并没有改变。您可以使用

例如,如果我执行一个Groovy脚本,该脚本修改字符串元类,添加一个方法foo()

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

GroovyShell shell2 = new GroovyShell();
Object result = shell2.evaluate("'a'.foo()");
在执行GroovyShell之后,有没有办法撤消所有元类更改?我试过了

shell1.getClassLoader().clearCache();

但这并没有改变。

您可以使用

GroovySystem.metaClassRegistry.removeMetaClass(String.class);
还原对字符串元类所做的所有更改


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

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


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

您也可以使用MetaClassRegistryCleaner

在进行元类更改之前,您可以

MetaClassRegistryCleaner registryCleaner = MetaClassRegistryCleaner.createAndRegister()
GroovySystem.metaClassRegistry.addMetaClassRegistryChangeEventListener(registryCleaner)
当您想要将元类更改重置为之前的状态时

你能行

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

通过这种方式,您可以重置在此期间所做的所有元类更改。

谢谢。但是,如果我不知道已经做了哪些元类更改,又会怎样呢。想象一下GroovyWeb控制台这样的应用程序,不同的用户在其中执行Groovy脚本。我希望这些用户不要干预。请参阅下面的我的答案,它解决了您不知道哪些元类已更改的问题。我可以通过一些类加载器混乱来做到这一点吗?@JohnMercier没有我上面的答案的帮助吗?在许多方面,这是一种比注册表清理更好的方法,尤其是允许并发执行。
MetaClassRegistryCleaner registryCleaner = MetaClassRegistryCleaner.createAndRegister()
GroovySystem.metaClassRegistry.addMetaClassRegistryChangeEventListener(registryCleaner)
registryCleaner.clean()  
GroovySystem.metaClassRegistry.removeMetaClassRegistryChangeEventListener(registryCleaner)