栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

6、Groovy拓展方法与对象的关联方式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

6、Groovy拓展方法与对象的关联方式

2021SC@SDUSC

Groovy拓展方法与对象的关联方式 问题引入

在上次的博客上分析Groovy的拓展方式时,我们举过这个例子:

String content = new File('config.txt').text
println content

我们知道text是IOGroovyMethods类里面的拓展方法,但这时,又有一个新的问题产生了,File类型怎么可以直接调用IOGroovyMethods里面的方法呢?就让我们在这节博客根据源码深入探讨一下这个问题。

Groovy反射

由于在String类型里面并没有text方法,所以我们可以排除掉直接调用的可能性,那么使用反射的可能性就大大提高了。在分析那些拓展封装的方法,我们发现都有闭包Closure closure这样的一个参数和一个self,例如:

//DefaultGroovyMethods类中,用于遍历对象中的所有元素
public static  List each(List self, @ClosureParams(FirstGenericType.class) Closure closure) {
        return (List)each((Iterable)self, closure);
    }

而在点击进入查看闭包Closure类后,发现它继承于GroovyObjectSupport类,点击进入后,在其实现的接口GroovyObject中发现了反射的代码:

  @Internal
    default Object invokeMethod(String name, Object args) {
        return this.getmetaClass().invokeMethod(this, name, args);
    }
     metaClass getmetaClass();
    void setmetaClass(metaClass var1);

可见,在Groovy中一般是通过反射的方式调用方法的,具体来讲是通过metaClass中的invokeMothod方法来进行反射调用的。但是,我们知道,在Java中,通过反射来调用方法,比直接调用方法会慢上几倍。所以在Groovy中调用优化的思想就是通过直接调用来代替反射调用。而要实现直接调用,则需要为DefaultGroovyMethods(以下简称DGM)中的每个方法生成一个从metaClass派生的包装类,该类的invoke方法将直接调用DGM中对应的方法。

优化的具体流程:
  1. 为DefaultGroovyMethods的每个方法生成一个包装类,该类继承GeneratedmetaMethod类,而GeneratedmetaMethod类则继承metaMethod类。该包装类的类名类似于org.codehaus.groovy.runtime.dgm 123 ( 123( 123(后跟一个数),在Groovy分发的jar包中可以找到总共918个这样的类,说明DGM中总共有918个方法。这些包装类的代码形式如下(以上面提到的each方法的包装类为例):
public class dgm$123 extends GeneratedmetaMethod {
    ...
    public Object invoke(Object object, Object[] arguments) {
        return DefaultGroovyMethods.each((Object) object, (Closure) arguments[0]); // 将各参数强制转换为对应的类型后,直接调用DefaultGroovyMethods中对应的方法
    }
    ...
}
  1. 当运行Groovy程序的时候,在metaClassRegistryImpl的实例初始化时,通过调用GeneratedmetaMethod.DgmMethodRecord.loadDgmInfo方法,为所有包装类创建GeneratedmetaMethod.Proxy实例作为其代理
//GeneratedmetaMethod中的静态方法
public static List loadDgmInfo() throws IOException 
//GeneratedmetaMethod的子类
 public static class Proxy extends GeneratedmetaMethod ;
  1. 在Groovy程序第一次调用DGM方法时,则由GeneratedmetaMethod.Proxy实例载入对应的包装类并实例化,然后调用其invoke方法。这样就实现了包装类的延迟加载,在一定程度上加快了程序初始化加载的速度。
评价:

Groovy通过这种反射的优化方法,即方便了使用,而且生产了Proxy实例,确保了不会产生大量的类,由于每个类都是需要占用内存的,所以会对JVM用于存放类信息的PermGen内存区域造成压力,容易产生OutOfMemoryError。而生产了Proxy实例之后之后,相当于一个使用池子了,每个包装类相当于移动热点,可以被多个使用这个方法的对象使用。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/292434.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号