Groovy08_MOP与元编程(方法拦截) ```
Posted 李樟清
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Groovy08_MOP与元编程(方法拦截) ```相关的知识,希望对你有一定的参考价值。
// java当中我们可以使用反射在运行的时候查看类的结构方法成员属性,
// 但是不能修改一个类的实现,不能动态的往类中去注入一个方法
// 而Groovy利用MOP元编程,可以做到这些,可以基于应用当前的状态,
// 动态的添加或者改变一些类的对象的方法和行为
// 比如一个类的一个方法我们没有写实现,可以通过服务器下发,吧这个方法的实现替换掉或者把里面的成员属性替换掉
// 由终端或者控制台服务器来操作这些行为
1. 第一种拦截方式
// 1. Person 是一个实现了GroovyObject的一个类
class Person
def name
def dream()
println 'i have a dream'
def p = new Person(name:'Zeking')
// 调用方法
p.dream() // i have a dream
p.invokeMethod('dream',null) // i have a dream
MetaMethod m = p.metaClass.getMetaMethod('dream',null)
m.invoke(p,null) // i have a dream
println '========================================================'
// 2. 进行拦截
// 实现GroovyInterceptable 接口 ,虽然这个接口没有任何的新增方法
// 但是我们实现了这个接口,我们在这个对象上调用任何方法
// 他会去调用到 invokeMethod 方法
class Person2 implements GroovyInterceptable
def name
def dream()
println 'p2 i have a dream'
Object invokeMethod(String name, Object args) // 这边成功进行了拦截
// println 'inovoke'
System.out.println 'p2 invoke'
def p2 = new Person2(name:'Zeking')
p2.dream() // Caught: java.lang.StackOverflowError
// 因为 Person2 实现了 GroovyInterceptable方法,所以当我们p2.dream()的时候
// 他不会去调用dream方法会去调用invokeMethod方法,而invokeMethod 被我们改变了行为,
// 行为是println 'inovoke' ,所以他不会去调用dream方法,而是调用println方法
// 又因为println 是 Grovvy 为我们注入到 Object 当中的 ,即为Person注入的方法,
// 而println 方法又会调用到invokeMethod 方法,所以层级太深了。我们可以用System.out.println 'invoke'
p2.dream1() // 调用不存在的方法也会 调用到invokeMethod 方法,
println '========================================================'
// 3. metaClass.invokeMethod 说明
class Person3 implements GroovyInterceptable
def name
def dream()
System.out.println 'p3 i have a dream'
Object invokeMethod(String name, Object args) // 这边成功进行了拦截
System.out.println 'p3 invoke'
//respondsTo(name) // 不能调用 respondsTo ,不然又会StackOverflowError
// 那怎么判断这个类有么有实现 方法
if (metaClass.invokeMethod(this,'respondsTo',name,args))
// 这是metaClass上面调用 invokeMethod方法 和在 Person3上面调用 invokeMethod方法有什么不一样的?
// metaClass 是定义class的行为,而在Person3 是定义Person3类型的对象行为
// metaClass 没有实现GroovyInterceptable 接口,是可以成功调用的
def p3 = new Person3(name:'Zeking')
p3.invokeMethod('dream',null)
// 没有实现GroovyInterceptable 接口 : p3 invoke ;
// 实现了GroovyInterceptable 接口: p3 invoke
p3.metaClass.invokeMethod(p3,'dream',null)
// 没有实现GroovyInterceptable 接口 :p3 i have a dream
// 实现了GroovyInterceptable 接口: p3 i have a dream
p3.dream()
// 没有实现GroovyInterceptable 接口 : p3 i have a dream
// 实现了GroovyInterceptable 接口: p3 invoke
println '========================================================'
// 4.
class Person4 implements GroovyInterceptable
def name
def dream()
System.out.println 'p4 i have a dream'
Object invokeMethod(String name, Object args) // 这边成功进行了拦截
System.out.println 'p4 invoke'
//respondsTo(name) // 不能调用 respondsTo ,不然又会StackOverflowError
// 那怎么判断这个类有么有实现 方法
if (metaClass.invokeMethod(this,'respondsTo',name,args))
metaClass.invokeMethod(this,name,null)
else
System.out.println 'p4 missing method'
def p4 = new Person4(name:'Zeking')
p4.dream()
// p4 invoke
// p4 i have a dream
println '========================================================'
// 应用
class Manager
static Manager instance
def isInit
static Manager getInstance()
if (null == instance)
synchronized (Manager.class)
if (null == instance)
instance = new Manager()
return instance
def init()
isInit = true
def dream()
if (isInit)
System.out.println 'm5 i have a dream'
class Manager2 implements GroovyInterceptable
static Manager2 instance
def isInit
static Manager2 getInstance()
if (null == instance)
synchronized (Manager2.class)
if (null == instance)
instance = new Manager2()
return instance
def init()
isInit = true
def dream()
if (isInit)
System.out.println 'm5 i have a dream'
Object invokeMethod(String name, Object args) // 这边成功进行了拦截
System.out.println 'm2 invoke'
if (name != 'init')
if(!isInit)
System.out.println 'please invoke init first'
return
if (metaClass.invokeMethod(this,'respondsTo',name,args))
metaClass.invokeMethod(this,name,null)
else
System.out.println 'p4 missing method'
Manager2.instance.dream()
// p4 invoke
// please invoke init first
Manager2.instance.init()
Manager2.instance.dream()
// m2 invoke
// m2 invoke
// m5 i have a dream
2. 第二种拦截方式
// 1.第一种方式:在单个对象上进行方法拦截
// def zeking = new Zeking() 针对对象而不会对类产生影响
// 2.第二种方式: 在类上进行方法拦截
// Zeking.metaClass
println '==============1.1================================='
class Zeking
def dream()
println "Zekign's dream"
// 1.1
def zeking = new Zeking()
zeking.dream() // Zekign's dream
zeking.metaClass.dream = // 用一个闭包替换掉
println 'replace dream'
zeking.dream() // replace dream
new Zeking().dream() // Zekign's dream
println '==============1.2================================='
// 1.2
class Zeking2
def dream()
println "2 : Zekign's dream"
def zeking2 = new Zeking2()
zeking2.metaClass.dream = // 用一个闭包替换掉
println '2 : replace dream'
// 如果我们覆盖了一个对象或者一个类的invokeMethod方法
// 那么它的实现就和 实现了GroovyInterceptable接口的类 一样了
// 不管调用了他的什么方法,都会调用到invokeMethod 里面去
zeking2.metaClass.invokeMethod =
String name, Object args->
System.out.println('2 : invoke')
zeking2.dream() // 2 : invoke
println '=============1.3=================================='
// 1.3
class Zeking3
def dream()
println "3 : Zekign's dream"
def zeking3 = new Zeking3()
zeking3.metaClass.dream = // 用一个闭包替换掉
println '3 : replace dream'
zeking3.metaClass.invokeMethod =
String name, Object args->
System.out.println('3 : invoke')
// metaClass 是谁的? 闭包默认的策略是Closure.OWNER_FIRST (回去看lsn4)
// 所以 这个闭包的OWNER 是 lsn8_1 的metaClass 不是 zeking3的 metaClass
// 所以 不能自己使用metaClass 要使用代理
// 默认的闭包他的 delegate 和 owner 是一样的
// 但是 覆盖方法使用metaClass,他的 delegate会变成调用metaClass的对象或者类,即zeking3的
def method = delegate.metaClass.getMetaMethod(name,args) // 用另一种方法,也可以继续使用 respondsTo
if (method)
method.invoke(delegate,args)
zeking3.dream() // 3 : invoke
// 3 : replace dream
println '=================1.4=============================='
// 1.4
// 不仅可以改变自己写的类 或者GDK的类,还可以改变 JDK的类
String.metaClass.plus =
CharSequence i ->
i
println "123"+'abc' // abc
println '==============2.1================================='
// 2.1
class Zeking10
def dream()
println "10 : Zekign's dream"
// 2.
def zeking10 = new Zeking10()
zeking10.dream() // 10 : Zekign's dream
Zeking10.metaClass.dream = // 用一个闭包替换掉
println '10 : replace dream'
zeking10.dream() // 10 : Zekign's dream
new Zeking10().dream() // 10 : replace dream
//println '==============================================='
3. propertyMissing methodMissing
// 1.propertyMissing methodMissing
class Man
def propertyMissing(String name)
return null
def propertyMissing(String name, def arg)
def methodMissing(String name, def args)
println 'methodMissing'
return 'dream' // 这个返回值是干嘛的,
def man = new Man()
man.dream() // methodMissing
println man.dream() // methodMissing
// dream
// 如果在一个类上实现了 methodMissing 方法的话,
// 我们 在一个类上调用不存在的方法,他会为
// 我们 调用到 methodMissing 方法
// 成员属性就是propertyMissing
4. 模拟 命令行输入,动态改变方法
class Man2
def dream()
println 'Man2 dream()'
def propertyMissing(String name)
return null
def propertyMissing(String name, def arg)
def methodMissing(String name, def args)
println 'methodMissing'
return 'dream' // 这个返回值是干嘛的,
def man2 = new Man2()
def scanner = new Scanner(System.in)
Thread.start
while (true)
def msg = scanner.nextLine()
if (msg == 'exit')
break
if (man2.respondsTo(msg))
man2."$msg"()
else
def (name,body) = msg.split(":")
man2.metaClass."$name" =
evaluate(body)
以上是关于Groovy08_MOP与元编程(方法拦截) ```的主要内容,如果未能解决你的问题,请参考以下文章
GroovyMOP 元对象协议与元编程 ( 方法合成引入 | 类内部获取 HandleMetaClass )
GroovyMOP 元对象协议与元编程 ( 方法委托 | 使用 @Delegate 注解进行方法委托 )
GroovyMOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 使用 MetaClass 进行方法拦截 | 对象上拦截方法 | 类上拦截方法 )