例如,如果我执行 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();
但这并没有带来改变。
你可以使用
GroovySystem.metaClassRegistry.removeMetaClass(String.class);
恢复对 String 元类所做的所有更改。
或者,您只能更改某个 String 实例的元类,因此并非所有 String 实例都会受到影响。
您也可以使用 MetaClassRegistryCleaner。
在进行一些元类更改之前,您可以这样做
MetaClassRegistryCleaner registryCleaner = MetaClassRegistryCleaner.createAndRegister()
GroovySystem.metaClassRegistry.addMetaClassRegistryChangeEventListener(registryCleaner)
当您想要将元类更改重置为之前的状态时。
你可以做
registryCleaner.clean()
GroovySystem.metaClassRegistry.removeMetaClassRegistryChangeEventListener(registryCleaner)
通过这种方式,您可以重置在此期间所做的所有元类更改。
我意识到这是一个有点老的问题,但这是我在搜索完全相同的问题时在 Google 上的第一个结果。
我选择的解决方案是将 groovy 放入新的类加载器中(通过使用 plexus-classworlds),因此当脚本完成时,类加载器将被释放(因此对元类的任何更改也会被释放)。
这是相关的,但更关注 Groovy 代码,而不是 shell。我还没有在那里尝试过,但至少在代码库中
您可以将其设置为空 如果你正在做单元测试,那么你有一个@Before和@After,你可以在方便的地方进行,我会推荐@After
// how you modify a method, notice args types must be the same but you can also only do an array if you are not going to use it
ClasName.metaClass.nameOfMethod{String arg1, Boolean arg2, String arg3 = "default" ->
println("Inside metaclass")
}
@After
void cleanUp()
{
ClasName.metaClass = null
}