Groovy MOP与元编程

2017-12-12  本文已影响154人  zhaoyubetter

参考:

《Groovy 程序设计》

元编程(metaprogramming)意味着编写能够操作程序的程序,包括操作程序自身;Groovy通过MOP(元对象协议 MetaObject Protocol)实现;

在Groovy中,使用MOP可以动态调用方法,可在运行时合成类和方法;

Groovy 对象

Groovy对象是带有附加功能的Java对象,在一个Groovy应用中,使用三类对象:

GroovyObject类

如果一个类,为Groovy所编译,通过发编译代码可发现,会实现GroovyObject接口,这样就使Java对象有了一些动态类;

public interface GroovyObject {
    Object invokeMethod(String name, Object args);
    Object getProperty(String propertyName);
    void setProperty(String propertyName, Object newValue);
    MetaClass getMetaClass();
    void setMetaClass(MetaClass metaClass);
}

getMetaClass()和setMetaClass使创建代理拦截POGO的调用,注入方法等有了可能;

  1. 对于POJO,Groovy维护了MetaClass的一个MetaClassRegistry;Groovy会去应用类去取它的MetaClass,并将方法调用委托给它;这样在它的MetaClass上定义的任何拦截器或方法优先于POJO原来的方法;
  2. 对于POGO,则有一个到其MetaClass的直接引用;如果没有实现GroovyInterceptable,则会先查找它的MetaClass中的方法,没有,则查找POGO自身上的方法,没有,则以方法名查找属性或字段,如果属性或字段是Closure类型的,则调用它;如果找不到,则抛出异常 missingMethod Exception

测试代码

    @Test  // metaClass 测试
    void testInterceptedMethodCAllOnPoJO() {
        def val = new Integer(3)
        val.metaClass.toString = { -> "intercepted" }
        assert "intercepted" == (val.toString())     // 被拦截
    }

    @Test  // 方法拦截
    void testInterceptableCalled() {
        def obj = new AnInterceptable()
        assert "intercepted" == obj.existingMethod()        // 存在的方法,拦截,执行invokeMethod()
        assert "intercepted" == obj.nonexistingMethod()     // 不存在的方法,拦截,执行invokeMethod()
    }
    class AnInterceptable implements GroovyInterceptable {
        def existingMethod() {"Hello"}      // 返回Hello无效,返回还是 "intercepted"
        def invokeMethod(String name, Object args) {"intercepted"}
    }

  // 拦截存在的某个方法
    @Test
    void testInterceptedExistingMethodCalled() {
        AGroovyObject.metaClass.existingMethod2 = { -> 'intercepted' }
        def obj = new AGroovyObject()
        assert 'intercepted' == obj.existingMethod2()
        assert 'existingMethod' == obj.existingMethod() // 此方法未拦截
    }

    class AGroovyObject {
        def existingMethod() { "existingMethod" }
        def existingMethod2() { "existingMethod2" }
        def closueProp = { "closure called" }
    }

    // 属性闭包调用
    @Test
    void testPropertyThatIsClosureCalled() {
        def obj = new AGroovyObject()
        assert 'closure called' == obj.closueProp()
    }
上一篇 下一篇

猜你喜欢

热点阅读