Gradle入门之Groovy元编程

1,143 阅读3分钟

系列文章往这看

gradle入门以及环境搭建

gradle入门之元编程

gradle入门之Groovy语法

gradle简介及生命周期

gradle核心之project

如何自己动手撸一个Gradle插件

gradle中的Transform是什么?

简介

Groovy的元编程是指groovy运行时,可以理解成编写代码所执行的时期,也就是Runtime。在比如有解释执行的Js,编译执行的java,还有运行时期执行的代码java反射。

Groovy运行时的处理逻辑如下图: untitled diagram.png

元编程

按照上图所示,我们可以自己写一个Demo,示例代码如下:

class Study {
    public static void main(String[] args) {
        def person = new Personal(name: "Silence", age: 26)
        println(person.printName())
        println(person.printAge())
        println(person.sex)
    }
}

class Personal {
    public String name
    public int age

    public String printName() {
        return "My name is $name"
    }

    public String printAge() {
        return "My ag is $age"
    }

}

输出结果如下:

My name is Silence
My ag is 26
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: sex for class: Personal
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:65)
	at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:87)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:329)
	at Study.main(Study.groovy:9)

可以看到前两个日志是正常输出的,第三个控制台则提示MissingPropertyException。也就是上图中,所以逻辑都没进去导致异常输出。

我们在看看如果我们复写invokeMethod方法时的输出效果,代码修改如下:

class Personal {
    public String name
    public int age

    public String printName() {
        return "My name is $name"
    }

    public String printAge() {
        return "My ag is $age"
    }

    @Override
    Object invokeMethod(String name, Object args) {
        return "this invoke method is $name,this params is $args"
    }

}

控制台输出如下:

My name is Silence
My ag is 26
this invoke method is sex,this params is []

然后我们看看重写methodMissing方法后:

class Personal {
    public String name
    public int age

    public String printName() {
        return "My name is $name"
    }

    public String printAge() {
        return "My ag is $age"
    }

    @Override
    Object invokeMethod(String name, Object args) {
        return "this invoke method is $name,this params is $args"
    }

    Object methodMissing(String name, Object args) {
        return "this Missing method is $name,this params is $args"
    }

}

输出结果如下:

My name is Silence
My ag is 26
this Missing method is sex,this params is []

可以看出,两个方法都重写时,优先调用methodMissing。如果找不到才会调用invokeMethod。

MetaClass

Metaclasses在方法解析中起到核心作用,对于来自groovy代码的每个方法调用,Groovy将找到给定对象的MetaClass,并通过MetaClass#invokeMethod将方法解析委托给Metaclasses,不应该与GroovyObject#invokeMethod混淆,后者恰好是Metaclasses最终可能调用的方法。

注入新字段

现在我们通过metaClass给Personal注入一个新属性看看:

  Personal.metaClass.sex = "男"
  def person = new Personal(name: "Silence", age: 26)
  println(person.printName())
  println(person.printAge())
  println(person.sex)

可以看出我们注入了一个sex的字段,输入结果如下:

My name is Silence
My age is 26

当然了,注入静态变量也是类似,加上static即可。

注入新方法

看到我们输入性别的时候,发现好像和上面对比,不工整,那就自己整一个工整的,修改代码:

        Personal.metaClass.sex = "男"
        Personal.metaClass.printSex = { ->
            "My sex is $sex"
        }
        def person = new Personal(name: "Silence", age: 26)
        println(person.printName())
        println(person.printAge())
        println(person.printSex())

输出结果可想而之:

My name is Silence
My age is 26
My sex is

这下工整了~。当然了,注入静态方法也是类似,加上static即可。

总结

可以看出,我们可以通过metaClass给类新增变量,新增方法。那么这个和直接在类这种提供有什么区别呢?
举个例子:引入第三方库,其中的某个类有我们想用的方法,但是这个方法又不够全,想给里面添加点自己的方法。通常是extends它进而扩展,但是如果是final 类,任何类不能继承它,只能用它已有的方法。这个时候groovy的动态添加就有了大展身手的地方。不修改、不继承,通过metaclass变相的对原有的类进行了扩展。

参考

groovy中的元编程Groovy笔记之元编程

本文首发于我的个人博客:Gradle入门之Groovy元编程

更多文章请关注我的公众号:码农职场