分享
  1. 首页
  2. 文章

用Go编写JVM之搜索class文件

x_zhaohu · · 1360 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

源于只因遇见Go,被Go的魅力所折服,慢慢将发生下面的故事

Java类加载机制

Java类加载器的作用,将class文件加载到内存。从Java开发人员的角度来说,类加载器可分为三种:

  • 启动类加载器(Bootstrap ClassLoader):加载<JAVA_HOME>/jre/lib下的jar
  • 扩展类加载器(Extension ClassLoader):加载<JAVA_HOME>/jre/lib/ext/下的jar
  • 应用程序类加载器(Application ClassLoader):加载用户自己编写的class

大多数的加载器使用双亲委派模型,双亲委派模型的工作过程是: 如果一个类加载器收到了类加载器的请求,它首先不会自己去尝试加载这类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。


类加载流程图.jpg

实现思路

  • 设置命令行参数,指定路径
  • 实现类路径:启动类加载器,扩展类加载器,应用程序类加载器
  • 将类路径抽象出来,这三个作为其子类

编码过程

编码过程从三方面介绍,首先是工程目录,让读者可以清晰看见。其次是运行效果,读者可根据实现的搜索class文件的效果如何,选择是否继续往下观看。源码请移步传送门

  • 工程目录
  • 运行效果
  • 代码实现

工程目录

  • gopath:代码存放区(workspace)
  • gopath/src:存放源码的区域
  • jvmgo:项目名
  • ch02:子文件
  • ch02/classpath/:这次主要编写的代码

project02.png

运行效果

ch02/下编译: go build -o readClass 后所在当前目录下便生成可执行文件readClass

验证通过启动类或扩展类加载器加载java.lang.Object,-Xjre是预定义的命令行参数,"/home/sprint/java/utils/jdk1.8.0_91/jre"指定jre路径,效果图如下:


02_result_01.png

验证通过应用程序类加载器加载ch02/Testclass(自己编写的类),如果不指定路径,默认当前路径。-cp是预定义的命令行参数,""代表当前目录,效果图如下:


02_result_02.png

代码实现

  • terminal.go中预定义Xjre命令行参数
//定义Termial结构体
type Terminal struct {
 //...省略字段,
 XjreOption string // 添加XjreOption字段
}
func parseTerminal() *Terminal {
 terminal := &Terminal{}
 //省略部分代码...
 flag.StringVar(&terminal.XjreOption, "Xjre", "", "path to jre")
 flag.Parse()
 //省略部分代码...
 return terminal
}
  • 编写类路径及其子类
    总类路径包含:启动类加载器路径,扩展类加载器路径,应用程序类加载器路径。在ch02/classpath/下编写classpath.go,定义类路径如下:

    type Classpath struct {
     //启动类加载器
     bootClasspath Entry
     //扩展类加载器
     extClasspath Entry
     //应用程序加载器
     userClasspath Entry
    }

    每种类加载器都有相同的方法,这时定义一个接口开表示类路径项。在ch02/classpath/下编写entry.go文件定义Entry接口:

    type Entry interface {
     //负责寻找和加载class
     readClass(className string) ([]byte, Entry, error) //Go函数或方法运行返回多个值
     //类似toString()
     String() string
    }

    DirEntry代表:应用程序类加载器,用于加载文件目录中的class。ZipEntry代表:应用启动类和扩展类加载器,用于加载jar/zip文件。CompositeEntryWildcardEntry代表:Entry的集合。在ch02/classpath下创建entry_dir.go, entry_zip.go,entry_composite.go,entry_wildcard.go文件实现Entry接口。Go的实现接口的方式与Java有所不同,想体验的话,动手实现下,体验下Go的魅力吧!由于考虑篇幅,所以接口具体实现不贴代码了,具体源码请移步传送门

  • 测试执行
    编写完上述代码后,更改ch02/main.go中的startJVM()函数来进行测试。
func startJVM(terminal *Terminal) {
 cp := classpath.Parse(terminal.XjreOption, terminal.cpOption)
 fmt.Printf("classpath:%v class:%v args:%v\n",
 cp, terminal.class, terminal.args)
 className := strings.Replace(terminal.class, ".", "/", -1)
 classData, _, err := cp.ReadClass(className)
 if err != nil {
 fmt.Printf("Could not find or load main class %s\n", terminal.class)
 }
 fmt.Printf("class data:%v\n", classData)
}

一切准备就绪后,在ch02文件下敲入go build -o readClass,便生成了readClass可执行文件。之后按照"运行效果图"中命令行进行执行测试吧!

小结与声明:一边进一步理解Java虚拟机,一边学习Go。知识主要来源于gitbook(下面有地址)和张秀宏老师的《自己动手编写Java虚拟机》,我的源代码与书上的源码稍微有些不同。

参考文献


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:x_zhaohu

查看原文:用Go编写JVM之搜索class文件

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1360 次点击
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏