掌握Gradle,还需要掌握这些知识--Groovy MOP

public static void main(String… args) {

CallSite[] var1 = $getCallSiteArray();

Object demo = var1[2].callConstructor(Demo1.class);

var1[3].call(demo);

var1[4].callStatic(Demo1.class, var1[5].call(demo, “A”, “B”));

}

}

我们发现,调用 foo() 方法时,并未执行 invokeMethod 中的逻辑,而Groovy中还有一个特殊的接口:GroovyInterceptable,如果实现它的话:

class Demo2 implements GroovyInterceptable {

def foo(String s) {

return “foo:$s”

}

def invokeMethod(String name, Object args) {

return “unknown method n a m e ( name( name({args.join(‘,’)})”

}

static void main(String[] args) {

def demo = new Demo2()

println demo.foo(“a”)

println demo.bar(“A”, “B”)

}

}

我们将得到如下结果:

Task :Demo2.main()

unknown method foo(a)

unknown method bar(A,B)

foo() 方法并未被分配!!, 这个场景很容易让我们联想到 Java的动态代理拦截、自行分配方法执行

methodMissing示例

class Demo3 {

def foo(String s) {

return “foo:$s”

}

def invokeMethod(String name, Object args) {

return “unknown method n a m e ( name( name({args.join(‘,’)})”

}

def methodMissing(String name, Object args) {

return “methodMissing n a m e ( name( name({args.join(‘,’)})”

}

static void main(String[] args) {

def demo = new Demo3()

println demo.foo(“a”)

println demo.bar(“A”, “B”)

}

}

按照前文的分派流程图,我们猜到结果为:

Task :Demo3.main()

foo:a

methodMissing bar(A,B)

而实现了 GroovyInterceptable 的情况下,就无法再利用methodMissing机制拦截,而是按照 GroovyInterceptable 走 invokeMethod拦截

class Demo4 implements GroovyInterceptable {

def foo(String s) {

return “foo:$s”

}

def invokeMethod(String name, Object args) {

return “unknown method n a m e ( name( name({args.join(‘,’)})”

}

def methodMissing(String name, Object args) {

return “methodMissing n a m e ( name( name({args.join(‘,’)})”

}

static void main(String[] args) {

def demo = new Demo4()

println demo.foo(“a”)

println demo.bar(“A”, “B”)

}

}

Task :Demo4.main()

unknown method foo(a)

unknown method bar(A,B)

动态处理类的属性

一个有关的题外话

一个传统的 简单JavaBean,在很多场景下又称为 POJO ,大家对此不会陌生,它包含了属性和属性的Getter、Setter并且不包含任意逻辑。

我们知道, POJO需要添加Getter、Setter,哪怕通过IDE生成,并且编译时如果可能,会被inline优化,为此,还有 是否该使用Lombok之争

但是,对于 “应当有Getter、Setter,但是不应当由编写者处理,而是应该由编译器处理” 是多数人认同的

Groovy中对此进行了尝试,提供了 GPath机制:通过编译器直接生成Getter、Setter,编码时形如属性访问,用"."符 foo.bar,实际却相对复杂。

kotlin中也有类似的机制。

class GpathDemo {

static class Foo {

String bar

def getBaz() {

return “baz”

}

}

static void main(String[] args) {

Foo foo = new Foo(bar:“bar”)

foo.bar = “bar 2”

println(foo.bar)

println(foo.baz)

}

}

我们可以发现,生成的类:

public static class Foo implements GroovyObject {

private String bar;

@Generated

public Foo() {

CallSite[] var1 = $getCallSiteArray();

super();

MetaClass var2 = this.$getStaticMetaClass();

this.metaClass = var2;

}

public Object getBaz() {

CallSite[] var1 = $getCallSiteArray();

return “baz”;

}

@Generated

public String getBar() {

return this.bar;

}

@Generated

public void setBar(String var1) {

this.bar = var1;

}

}

public static void main(String… args) {

CallSite[] var1 = $getCallSiteArray();

GpathDemo.Foo foo = (GpathDemo.Foo)ScriptBytecodeAdapter

.castToType(var1[0].callConstructor(GpathDemo.Foo.class,

ScriptBytecodeAdapter.createMap(new Object[]{“bar”, “bar”})),

GpathDemo.Foo.class);

String var3 = “bar 2”;

ScriptBytecodeAdapter.setProperty(var3, (Class)null, foo, (String)“bar”);

var1[1].callStatic(GpathDemo.class, var1[2].callGetProperty(foo));

var1[3].callStatic(GpathDemo.class, var1[4].callGetProperty(foo));

}

读者可能已经注意到了,通过手动添加Getter,也可以利用GPath机制,用"."访问;

另外,读者可能也注意到:设置bar属性时,并未直接访问Setter,此处,我们可以动态的添加属性!

class GpathDemo {

static class Bar {

}

static void main(String[] args) {

Bar.metaClass.“getBaz” = { ->

return “baz”

}

Bar bar = new Bar()

println(bar.baz)

}

}

从编译结果看:

public static class Bar implements GroovyObject {

@Generated

public Bar() {

CallSite[] var1 = $getCallSiteArray();

super();

MetaClass var2 = this.$getStaticMetaClass();

this.metaClass = var2;

}

}

// main:

public static void main(String… args) {

CallSite[] var1 = $getCallSiteArray();

final class _main_closure1 extends Closure implements GeneratedClosure {

public _main_closure1(Object _outerInstance, Object _thisObject) {

CallSite[] var3 = $getCallSiteArray();

super(_outerInstance, _thisObject);

}

public Object doCall() {

CallSite[] var1 = $getCallSiteArray();

return “baz”;

}

}

_main_closure1 var4 = new _main_closure1(GpathDemo.class, GpathDemo.class);

ScriptBytecodeAdapter.setProperty(var4, (Class)null,

var1[5].callGetProperty(GpathDemo.Bar.class), (String)“getBaz”);

GpathDemo.Bar bar = (GpathDemo.Bar)ScriptBytecodeAdapter.castToType(

var1[6].callConstructor(GpathDemo.Bar.class),

GpathDemo.Bar.class);

var1[7].callStatic(GpathDemo.class, var1[8].callGetProperty(bar));

}

此时,在运行期增加了属性!

如果对Kotlin的扩展和代理比较熟悉,此处应该不难理解

但Groovy的设计更加有趣:

追踪:

  • org.codehaus.groovy.runtime.InvokerHelper#getProperty

  • org.codehaus.groovy.runtime.InvokerHelper#setProperty

发现会进入:GroovyObject,前面已经接触过

public interface GroovyObject {

Object invokeMethod(String var1, Object var2);

Object getProperty(String var1);

void setProperty(String var1, Object var2);

MetaClass getMetaClass();

void setMetaClass(MetaClass var1);

}

那么借助集合,如 Map ,并复写 getPropertysetProperty,就可以做一些有趣的事情

特殊的Expando类

哈哈,这个有趣的事情Groovy已经做了,这就是 Expando 类。

class ExpandoDemo {

static void main(String[] args) {

Expando expando = new Expando()

expando.foo = “foo”

println(expando.foo)

expando.bar = “bar”

println(expando.bar)

expando.properties.forEach(new BiConsumer() {

@Override

void accept(Object o, Object o2) {

println(“key: o , v a l u e : o,value: o,value:o2”)

}

})

}

}

Task :ExpandoDemo.main()

foo

bar

key:bar,value:bar

key:foo,value:foo

利用ExpandoMetaClass实现Mixin机制

Mixin 即 Mix In,混合, 我们可以笼统地认为:Mixin 即为 在一个类中混入其他类的内容

  • 对于支持多继承的语言,往往是在讨论 多继承 的问题;

  • 对于单继承的语言,Java是利用 接口 制造多继承的表现,基于 组合委托 等方式在目标类中 混入

规格继承 变相解决问题;Ruby 等语言则引入 Minin实现继承 变相解决问题。

我们不再对此概念进行纠缠,可以认为 “多继承语言可以解决很多问题并带来更多的关联问题,单继承语言想要好处又要规避坏处,部分语言提出了Minin机制”

而Groovy的Minin,除了 编译期 要能混入,还要 运行期混入

看个例子,虽然它的场景很不合理,你一定有一万种理由劝说我使用各类设计模式,但不要较真

class MixinDemo {

static class Paint {

def draw(Drawable drawable) {

println(“paint ${drawable.name}”)

}

}

static class Drawable {

String name

}

static void main(String[] args) {

def paint = new Paint()

Drawable.metaClass.draw = paint.&“draw”

def drawable = new Drawable(name: “test”)

drawable.draw(drawable)

}

}

例子中,我们动态的给Drawable添加了draw方法

如果我们将这一过程适当的封装:

class MixinDemo2 {

static class MixinDelegate {

private targetClass

MixinDelegate(targetClass) {

this.targetClass = targetClass

}

def mixin(String asMethodName, Closure closure) {

targetClass.metaClass.“$asMethodName” = closure

}

}

static void main(String[] args) {

def mixin = new MixinDelegate(MixinDemo.Drawable)

mixin.mixin(“draw”,new MixinDemo.Paint().&“draw”)

def drawable = new MixinDemo.Drawable(name: “test”)

drawable.draw(drawable)

}

}

这将会变得很有趣!!!

假设我们有一套 控制协议 ,在此之前,我们只能在编译期决定好 指令的执行 – 即控制协议实现,即使运用一些巧妙的设计模式,自由程度也很低, 但现在可以在运行时更为自由地扩展、修改

当然,结合前面的知识,我们可以让它更加的酷炫:

class MixinDemo3 {

static class MixinDsl implements GroovyInterceptable{

private targetClass

MixinDsl(targetClass) {

this.targetClass = targetClass

}

def invokeMethod(String s, o) {

if (s.startsWith(“mixinFun”) && s.length() > 8 && o[0] instanceof Closure) {

def methodName = s[8].toLowerCase() + s[9…-1]

targetClass.metaClass.“$methodName” = o[0]

return null

} else {

println(“cannot handle”)

}

}

}

static void main(String[] args) {

(new MixinDsl(MixinDemo.Drawable)).mixinFunDraw new MixinDemo.Paint().&“draw”

def drawable = new MixinDemo.Drawable(name: “test”)

drawable.draw(drawable)

}

}

此时,添加方法的写法呈现出 DSL的风格

运行时的其他修改

前面我们已经学习了在运行时给类添加方法,接下来再了解更多的内容:

添加构造器

这个例子要和Java进行对比

class RuntimeDemo {

static class Bean {

String a

String b

String c

String d

@Override

public String toString() {

return “Bean{” +

“a='” + a + ‘’’ +

“, b='” + b + ‘’’ +

“, c='” + c + ‘’’ +

“, d='” + d + ‘’’ +

‘}’;

}

}

static class ConstructorDemo {

void main() {

Bean.metaClass.constructor = { String a ->

new Bean(a: a, b: “b”, c: “c”, d: “d”)

}

def bean = new Bean(“a”)

println(bean)

}

}

static void main(String[] args) {

def bean = new Bean(a: “a”, b: “b”, c: “c”)

println(bean)

new ConstructorDemo().main()

}

}

本身Groovy允许我们在构造时设置属性值,但这并不是有重载的构造器!如果没有这个机制,我们就不得不建立一系列重载的构造器,或者老老实实赋值。

但Groovy可以添加构造器

添加静态方法

类比前面提到的添加方法,我们只需要添加关键字 static 就可以添加静态方法。

static void main(String[] args) {

GpathDemo.Foo.metaClass.‘static’.hello = { args1 ->

return “RuntimeDemo:hello,${args1}”

}

println GpathDemo.Foo.hello(“foo”)

}

为对象添加方法

前文已经介绍过给类添加方法,不再赘述。这里注意,我们可以单独给对象添加方法,而不累及该类的其他实例。

static void main(String[] args) {

def bean = new Bean(a: “a”, b: “b”, c: “c”)

//为对象添加方法

try {

bean.hello()

} catch(Exception e) {

println(e.message)

}

def emc = new ExpandoMetaClass(Bean.class, false)

emc.hello = { println “hello” }

emc.initialize()

bean.metaClass = emc

bean.hello()

try {

new Bean().hello()

} catch(Exception e) {

println(e.message)

}

}

很显然,第一次得到Exception,第二次正常打印hello,第三次得到Exception

自省

前文讲了如此之多的运行时修改,很显然,Groovy可以自省,我们简单了解一下以下知识,毕竟这些内容使用不多。

反射

Groovy承袭了Java,那么自然可以使用Java的反射,但是注意:

基于MOP添加的内容,均无法通过Java反射获知

respondsTo 和 hasProperty

class ResponseToDemo {

static class Demo {

def p = “p”

def foo() {

println(“foo”)

}

}

static void main(String[] args) {

Demo.metaClass.“bar” = { ->

println ‘bar’

}

def demo = new Demo()

if (demo.metaClass.respondsTo(demo, ‘bar’)) {

println ‘bar ok’

}

if (demo.metaClass.respondsTo(demo, ‘foo’)) {

println ‘foo ok’

}

if (demo.metaClass.hasProperty(demo, ‘p’)) {

println ‘p ok’

}

}

}

//> Task :ResponseToDemo.main()

//bar ok

//foo ok

//p ok

利用respondsTo和hasProperty,可以分析固有属性、方法以及MOP添加的内容。

hasMetaMethod 和 hasMetaProperty

这里直接给出结论:

这一组方法仅可对类进行分析,而针对对象利用MOP添加的属性和方法,利用respondsTo和hasProperty 可以分析得到。

借助Interceptor实现AOP能力

相信各位对AOP(Aspect-Orient-Program)都有或多或少的了解,在Java中也有大名鼎鼎的AspectJ,而在Groovy中, 本身就可以利用 Interceptor机制 进行简单的AOP,而不必借助框架的力量。

看一个简单的例子:

class InterceptorDemo {

static class Demo {

void foo() {

println(“foo”)

}

}

static class DemoInterceptor1 implements Interceptor {

@Override

Object beforeInvoke(Object o, String s, Object[] objects) {

println(“before $s”)

return o

}

@Override

Object afterInvoke(Object o, String s, Object[] objects, Object o1) {

println(“after $s”)

return o1

}

@Override

boolean doInvoke() {

return true

}

}

static void main(String[] args) {

def proxy = ProxyMetaClass.getInstance(Demo)

proxy.interceptor = new DemoInterceptor1()

proxy.use {

def demo = new Demo()

demo.foo()

先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以扫码领取!!!!

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
第一,学习知识比较碎片化,没有合理的学习路线与进阶方向。
第二,开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

mo = new Demo()

demo.foo()

先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-82PMdjeJ-1711295153839)]

[外链图片转存中…(img-cQnNCeYx-1711295153840)]

[外链图片转存中…(img-lnQ95gfQ-1711295153840)]

[外链图片转存中…(img-xogJrxqi-1711295153840)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以扫码领取!!!!

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

[外链图片转存中…(img-UGV3CprT-1711295153840)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-wRtLAD6l-1711295153840)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
第一,学习知识比较碎片化,没有合理的学习路线与进阶方向。
第二,开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值