Groovy元编程MOP(ExpandoMetaClass:EMC)的应用场景
发布时间:2020-12-14 16:54:11 所属栏目:大数据 来源:网络整理
导读:使用ExpandoMetaClass和Category可以实现元编程。ExpandoMetaClass可以动态添加和修改类的构造器,方法和属性。Category只能动态添加和修改类的方法。 当使用EMC动态添加或修改方法时,闭包Closure作为方法体被传入,它的delegate指向调用此方法的实例。 具
使用ExpandoMetaClass和Category可以实现元编程。ExpandoMetaClass可以动态添加和修改类的构造器,方法和属性。Category只能动态添加和修改类的方法。 当使用EMC动态添加或修改方法时,闭包Closure作为方法体被传入,它的delegate指向调用此方法的实例。 具体使用可参考:http://www.groovyq.net/node/75 ? 1、为类添加方法(为String类添加String times(int count)方法)
String.metaClass.times = {
int count -> String str = "
"
for (
int i = 0; i < count; i++) { str +=
delegate }
return str } assert "
hellohellohello","
hello".times(3)
2、为类添加重载方法(为String类添加String times()方法)
String.metaClass.times << {->
return
delegate }
3、为类修改方法(将String类的toUpperCase改成toLowerCase)
String.metaClass.toUpperCase = {->
return
delegate.toLowerCase() } assert "
hello","
heLLO".toUpperCase()
4、反射拿到方法的元型
String.metaClass.invokeMethod = {String mName,mArgs -> def m = String.metaClass.getMetaMethod(mName,mArgs)
if (mName != "
concat" && mName != "
toUpperCase")
return m.invoke(
delegate,mArgs)
long s = System.currentTimeMillis(); def result = m.invoke(
delegate,mArgs)
long e = System.currentTimeMillis();
long duration = e - s; println("
MOP耗费时间:" + duration);
return result; }
5、为单个实例添加或修改方法
String instance = "
hi" instance.metaClass.times = {
int count -> String str = "
"
for (
int i = 0; i < count; i++) { str +=
delegate }
return str } println instance.times(3) println "
he".times(3)
// MissingMethodException
6、一次添加多个方法
String.metaClass { times {
int count -> String str = "
"
for (
int i = 0; i < count; i++) { str +=
delegate }
return str } toUpperCase {->
return
delegate.toLowerCase() } }
7、添加或修改静态方法(为String类添加static String twice(String val))
String.metaClass.
static.twice = {String val ->
return val + val } assert "
hellohello",String.twice("
hello")
8、添加或修改构造器
class MOP { String val def print() { println val } } MOP.metaClass.constructor << {String val ->
return
new MOP(val: val) }
new MOP("
hello").print()
?
9、为类添加属性
MOP.metaClass.title = "
title"
10、为类添加只读属性(即只添加get方法)
MOP.metaClass.getTitle = {-> "
title"}
11、去掉元编程,只需将metaClass置为null即可String.metaClass = null 12、可以在使用static方法时,用use块简化代码
use(org.apache.commons.lang.time.DateUtils) {
new Date().addDays(1) //这里实际调用的是static Date addDays(Date date,int amount)方法 }也可以一次使用多个类的static方法
use(org.apache.commons.lang.time.DateUtils,org.apache.commons.lang.StringUtils) {
new Date().addDays(1) "
stringUtils".capitalise() }
既然EMC提供了运行期动态添加修改方法和属性的能力,我们可以用在什么地方呢? 1、有时候为了调试经常会调用System.out.println(XXXX),每次写这么长太烦了,如果变成XXXX.out()是不是就方便多了。
只需要为String、Integer等类添加一个out方法即可实现:
String.metaClass.out = {-> System.out.println(
delegate) } "
hello".out()
2、有时候为了从url获取数据(http GET方法),要是使用HttpClient得写一堆代码,如果变成调用"$url".httpGet()能直接获取响应报文该多爽啊。其实只需要给String添加一个httpGet方法即可:String.metaClass.httpGet = {-> //用HttpClient实现} 3、同样在实现执行系统命令的时候也可以这么做。类似这种需求是无穷无尽的,都可以用MOP简单实现。3.times { println "hello!" }list << "a string"def range = 1..9。。。。。。Groovy里面这些看似很神奇的语法其实都是通过MOP实现的。 4、用MOP实现AOP用MOP可以实现方法拦截,对源代码丝毫没有侵入性。比如想知道String的toUpperCase方法执行效率就可以用MOP。也可以捕获异常输出到日志中,而不影响源代码的执行。但是需要注意,如果应用层是用反射调用执行的,MOP就拦截不到了。 5、配置开关比如系统要构建xml,调试时为了xml语意清晰可以在生成xml时加上comment备注,但是系统上线真正运营时这些comment就没什么用了,这时可以用MOP关掉commment。具体代码自己实现。可以将这个功能写成一个函数,系统启动是调一下这个函数就关闭comment了。函数调用可以用Spring类配置。这样就可以用配置方式实现功能开关了。 ? 6、DSL(略) ? 还有更多的应用场景,希望大家一块讨论。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |