如前所述,MetaClass在方法解析中起着核心作用。对于来自groovy代码的每个方法调用,groovy将找到给定对象的MetaClass,并通过groovy.lang.MetaClass#invokeMethod(java.lang.Class,java.lang.Object,java.lang.String,java.lang.Object,boolean,boolean))将方法解析委托给MetaClass,groovy.lang.MetaClass#invokeMethod(java.lang.Class,java.lang.Object,java.lang.String,java.lang.Object,boolean,boolean))不应与groovy.lang.GroovyObject#invokeMethod(java.lang.String,java.lang.Object))混淆,groovy.lang.GroovyObject#invokeMethod(java.lang.String,java.lang.Object))恰好是元类最终可能调用的方法。

1.默认的metaclass的MetaClassImp

默认情况下,对象获取实现默认方法查找的MetaClassImpl实例。这种方法查找包括在对象类(“常规”方法)中查找方法,但如果没有以这种方式找到方法,则会求助于调用methodMissing,最终调用groovy.lang.GroovyObject#invokeMethod(java.lang.String,java.lang.Object))

  1. class Foo {}
  2. def f = new Foo()
  3. assert f.metaClass =~ /MetaClassImpl/

2.自定义metaclasses

您可以更改任何对象或类的metaclass,并将其替换为 Metaclassgroovy.lang.MetaClass的自定义实现。通常,您需要扩展一个现有的metaclass,例如MetaClassImplDelegatingMetaClassExpandoMetaClassProxyMetaClass;否则,您将需要实现完整的方法查找逻辑。在使用新的metaclass实例之前,应该调用groovy.lang.MetaClass#initialize()),否则元类的行为可能会或可能不会像预期的那样。

2.1.委托metaclass

如果您只需要装饰现有的Metaclass,则可以DelegatingMetaClass简化该用例。旧的元类实现仍然可以通过super轻松地对输入应用预转换、路由到其他方法和后处理输出来访问。

class Foo { def bar() { "bar" } }

class MyFooMetaClass extends DelegatingMetaClass {
  MyFooMetaClass(MetaClass metaClass) { super(metaClass) }
  MyFooMetaClass(Class theClass) { super(theClass) }

  Object invokeMethod(Object object, String methodName, Object[] args) {
     def result = super.invokeMethod(object,methodName.toLowerCase(), args)
     result.toUpperCase();
  }
}


def mc =  new MyFooMetaClass(Foo.metaClass)
mc.initialize()

Foo.metaClass = mc
def f = new Foo()

// 新的metaclass路由 BAR()和bar()的大写字母表示
assert f.BAR() == "BAR"

2.2.魔法包

可以在启动时更改元类,方法是为元类提供精心编制的(魔术)类名和包名。为了更改LLnteger的元类,在类路径中放置一个类mmletaclasetclass就足够了。例如,如果您想在框架执行代码之前更改元类,这在使用框架时非常有用。魔术包的一般形式是GGaclass。在下面的示例中,[包]是JJavalang,[类]是整数: