文章目录
元对象协议(MOP)
- 在java中使用反射可以在运行时探索程序的结果,类、方法、参数等。但是我们仍然局限于所创建的静态结果。无法在运行时修改一个对象的类型,或是让它动态获得行为。如果可以基于应用的动态状态或基于应用所接受的输入,动态地添加方法和行为,代码会变得更灵活,在groovy中元编程就提供了这一功能
- 元编程意味着编写能够操作程序的程序,包括操作程序自身。像Groovy这样的动态语言通过元对象协议(MOP:MetaObject Protocol)提供了这种能力。在Groovy中使用MOP可以动态调用方法,甚至在运行时合成类和方法。
- groovy对象是带有附加功能的java对象,在Groovy中,Groovy对象比编译好的java对象具有更多的动态行为。此外,对于java对象和Groovy对象上的方法调用,Groovy的处理方式也是不同的。
- POJO(java对象)、POGO(groovy编写的对象,扩展了java.lang.Object,同时也实现了groovy.lang.GroovyOBject接口)、Groovy拦截器是扩展了
GroovyInterceptable
的Groovy对象,具有方法拦截功能 GroovyInterceptable
是一个标记接口,对于实现了该接口的对象而言,其上的所有方法调用,不管是存在的还是不存在的,都会被它的invokeMethod()方法拦截。- Groovy支持POJO和POGO进行元编程,对于POJO,groovy维护了MetaClass的一个MetaClassRegistry。POGO有一个其到MetaClass的直接引用。当我们调用一个方法时,Groovy会检查目标对象是一个POJO还是一个POGO,对于不同的对象类型,Groovy的方法处理是不同的。对于POJO,Groovy会去应用类的MetaClassregistry取它的MetaClass,并将方法调用委托给它。因此我们在它的MetaClass上定义的任何拦截器或方法,都优先于POJO原来的方法
7.对于POGO,Groovy会采取一些额外的步骤。如果对象实现了GroovyInterceptable
接口,那么所有的调用都会被路由给它的invokeMethod()
,类似AOP
GroovyObject接口
-
groovy.lang.GroovyObject
是Groovy中的主要接口,就像Object类是Java中的主要接口一样。GroovyObject
在groovy.lang.GroovyObjectSupport
类中有一个默认实现,它负责将调用传递给groovy.lang.MetaClass
对象。 GroovyObject源代码如下: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); }
invokeMethod
-
当调用的方法不存在于Groovy对象上时,将调用此方法
class Person { def run() { println "run" } /** * 当您调用的方法不存在于Groovy对象上时,将调用此方法 */ def invokeMethod(String name, Object args) { println "called invokeMethod $name $args" } } def person = new Person() //输出:run person.run() //输出:called invokeMethod eat [] person.eat()
get/setProperty
-
对属性的每个读取访问都可以通过覆盖当前对象的getProperty()方法来拦截,覆盖setProperty()方法来拦截对属性的写访问权限:
class User { def username = "jannal" def age = 10 def idCard def getProperty(String name) { if (name != 'password') //将请求转发到getter以获取除password之外的所有属性。 return metaClass.getProperty(this, name) else return '123456' } def getAddress(){ return "Beijing" } //setProperty()方法来拦截对属性的写访问权限: void setProperty(String name, Object value) { this.@"$name" = '4574' } } def user = new User() //jannal println user.username //10 println user.age //Beijing println user.address //123456 println user.password user.idCard = "411522199111114578" //4574 println user.idCard
get/setMetaClass
-
访问对象的metaClass或设置自己的MetaClass实现以更改默认拦截机制。 例如,您可以编写自己的MetaClass接口实现,并将其分配给对象,从而更改拦截机制:
// getMetaclass someObject.metaClass // setMetaClass someObject.metaClass = new OwnMetaClassImplementation()
get/setAttribute
-
此功能与
MetaClass
实现相关。 在默认实现中,您可以访问字段而不调用它们的getter
和setter
class Customer { def username = "jannal" def age = 10 def getUsername(){ return "jannal2" } def setAge(def age){ this.age = "100" } } def customer = new Customer() //jannal2 println customer.username println customer.age //jannal println customer.metaClass.getAttribute(customer, 'username') //10 println customer.metaClass.getAttribute(customer